Comparar commits
286 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 83f1ccb8ad | |||
| cea401c513 | |||
| 6b54c1b6d4 | |||
| 193c4a953e | |||
| d389134036 | |||
| d8b140e341 | |||
| 5931e1143b | |||
| e6d0c4b79f | |||
| 44a4a18320 | |||
| 2f96506a6e | |||
| f904606b32 | |||
| 99bb14680a | |||
| 83df3dda95 | |||
| 5e4d67209c | |||
| 2798af1668 | |||
| f0e41ce4c7 | |||
| 300602dd32 | |||
| 136f6778e2 | |||
| 2fa7907054 | |||
| f3803c4c22 | |||
| 5d37927b0a | |||
| 6227f5cfa2 | |||
| 9fbb9fa5e1 | |||
| de81ee7ee6 | |||
| 5fcf971e28 | |||
| 492f70fc4b | |||
| 3ced7b7212 | |||
| 7b55867ea7 | |||
| 3e15ef1c86 | |||
| 0cdc836054 | |||
| 1aad62b95d | |||
| ed1c88920e | |||
| e6ca20c4a2 | |||
| cfa3470df6 | |||
| 479f297cf6 | |||
| 7e1b222f90 | |||
| 69baa6ea1a | |||
| 0fce93be37 | |||
| 51611ec2bb | |||
| 228a78136d | |||
| 34d10ace7a | |||
| 57bd0a5628 | |||
| 42e4860855 | |||
| ea1c9f70d7 | |||
| d3085b0450 | |||
| 63d02f1d5f | |||
| dfecbe5bfa | |||
| bcf9f00de5 | |||
| a8e8e35678 | |||
| 2ec4a8b4ce | |||
| 6c3d3dee81 | |||
| 40b3116ed7 | |||
| df7582b138 | |||
| b08dab9aa1 | |||
| da5a4804df | |||
| d12f43498e | |||
| f9f2facd76 | |||
| eaee3954c1 | |||
| eb235e11b6 | |||
| 0c5fe61ed3 | |||
| 76052b443a | |||
| 5a48248e1e | |||
| bedff3278f | |||
| 0bb48153a5 | |||
| b75246e3ca | |||
| 2d31f0d7fe | |||
| 87cfca721e | |||
| 54d36f3337 | |||
| a4a17d171a | |||
| 7c2673fc66 | |||
| c77ecbb10f | |||
| f0ba57ba23 | |||
| 893aa80361 | |||
| 59ac3d1d45 | |||
| 247a9478c8 | |||
| 1c64d858c2 | |||
| 91a1d7faaf | |||
| 214bbfa7b6 | |||
| 3ee4492b3c | |||
| 38c453b3c6 | |||
| 3d41c61991 | |||
| 1f9f47f97e | |||
| 41cc2923b1 | |||
| 4c180f3eed | |||
| 5f9a64dbea | |||
| 9d37bfdcf1 | |||
| d738c3aca6 | |||
| 836c4313ab | |||
| 91c6478add | |||
| fce527a55b | |||
| 9a1f62fc1f | |||
| 018d8656d3 | |||
| 2636e1ba45 | |||
| caed07dfc1 | |||
| 373cf3328d | |||
| 0370c3fa01 | |||
| f5143a7d63 | |||
| 346b2a27cb | |||
| 38281e6361 | |||
| 6e8413f568 | |||
| cb04364381 | |||
| 83d2555123 | |||
| 0ace97c8d4 | |||
| 9e3a0c61b8 | |||
| 2fda5c7873 | |||
| e29868c8ce | |||
| ac560be870 | |||
| 5a29cbf4a7 | |||
| dc77894f68 | |||
| 74432a6b9d | |||
| 2b2fa7e77c | |||
| c3f71b33aa | |||
| 927aae72d1 | |||
| 2a674f4e8d | |||
| 0b86ce2bda | |||
| 548a0709f4 | |||
| da84c0bb4d | |||
| 9e68a5b9ab | |||
| 6982bdaa28 | |||
| c1809232fe | |||
| 3c06c82eb7 | |||
| 1bcccb3134 | |||
| cdf49dc87e | |||
| 0a0fb8f803 | |||
| 60cfd56369 | |||
| 73050d38c5 | |||
| c50e941972 | |||
| 7c59fd21e2 | |||
| b095a4221c | |||
| 1ef39fa3b8 | |||
| fcf4530d83 | |||
| 0515e14d27 | |||
| ddbef0bd79 | |||
| bc5d31f86a | |||
| 09147a2aab | |||
| a75a119e2f | |||
| c1b3546161 | |||
| 8338432c7b | |||
| 8beae065cf | |||
| 0e7d39aa13 | |||
| 74063ad735 | |||
| 55a29808c9 | |||
| 40f3de3939 | |||
| 5d94ab09e3 | |||
| b34ff6853d | |||
| e2570be957 | |||
| 95e6fff3da | |||
| 9de12b7385 | |||
| beffe906e4 | |||
| e850d1073d | |||
| c02a2ba5ba | |||
| f92bb6690b | |||
| 5842a3bba6 | |||
| fcf691d97c | |||
| a32c7d5f07 | |||
| edfb18b75a | |||
| 5544c5d5d4 | |||
| 22100f7c3a | |||
| 8ece01ccda | |||
| 9b68039a62 | |||
| a914326e75 | |||
| 2b7dd35e05 | |||
| 15e41169ad | |||
| f8c5219c12 | |||
| c570b67dda | |||
| 456fac1700 | |||
| 41e58c394b | |||
| 5aeda5f67b | |||
| c96adf168c | |||
| 40c5bc01ff | |||
| 09dabef70c | |||
| 96edee806e | |||
| e58f4683d1 | |||
| 9750817bf0 | |||
| 7099d730e6 | |||
| 13c290e99f | |||
| cf37966e39 | |||
| 9449c4b9b5 | |||
| 046172e5d9 | |||
| c74446e38c | |||
| 7897460993 | |||
| 4b59583bca | |||
| 41f73559f2 | |||
| d3090c0965 | |||
| dc5caebbf8 | |||
| 14280dfedb | |||
| 8fdf11135a | |||
| c8baa8f349 | |||
| a6e25b46af | |||
| 395d14ab58 | |||
| 0d4b57df7a | |||
| 416e7617b3 | |||
| 838c470017 | |||
| f0a09665db | |||
| 1397fa64d5 | |||
| ac17a6afcf | |||
| 35af1bab30 | |||
| 1fe7bb271a | |||
| 774e25d944 | |||
| 6770e8541d | |||
| 70e94e4dde | |||
| 0ffbc6e345 | |||
| 25e796753f | |||
| 70d9ef4f77 | |||
| fd67c9a589 | |||
| f0917ff774 | |||
| 843281dec0 | |||
| 3a21588429 | |||
| 21eeb09a3c | |||
| 900c5ed358 | |||
| 195c8a92d1 | |||
| 7c651e6093 | |||
| 860b899f0c | |||
| 87b7524de9 | |||
| 29641ae16a | |||
| 02e32a7a9d | |||
| 3056369c6e | |||
| 3da75726d3 | |||
| b7346de47d | |||
| 7a69100b2f | |||
| 2732d2b9d3 | |||
| 87bb27cc4f | |||
| bafa300b0f | |||
| 939cf4542f | |||
| 874975da54 | |||
| f0bebd4c33 | |||
| c444a11862 | |||
| 4c0704e338 | |||
| 77f4cd5d58 | |||
| 9858d3c5a8 | |||
| 414acbc9ec | |||
| 21f904db42 | |||
| f6ca253849 | |||
| 3f989191e3 | |||
| 2bea014e89 | |||
| 84fc19a75f | |||
| d803924ef0 | |||
| 889f8d9d30 | |||
| 1dcb7eaf1f | |||
| 5f9e4ace2f | |||
| 6386330973 | |||
| fd89b9755e | |||
| 730f454278 | |||
| e2fca29c91 | |||
| f97a222cf5 | |||
| c75105e977 | |||
| 7096471d65 | |||
| cc1cee8a38 | |||
| 5f2680889f | |||
| b3ae8bb606 | |||
| 72d9f37845 | |||
| fdfccafd84 | |||
| a784f946ba | |||
| a04af6c4bd | |||
| 64b24a96c8 | |||
| a62a5d0d7b | |||
| 3043d1e839 | |||
| a3aefb6902 | |||
| a42aaa270c | |||
| f8b471c17b | |||
| 87adff44db | |||
| 767bba9c04 | |||
| 0c827521d0 | |||
| 80cec7d12f | |||
| 5f916357e9 | |||
| ea82eea9bb | |||
| 22222d7db4 | |||
| cebee369d1 | |||
| faf809851c | |||
| d05aafd76b | |||
| 8d52721873 | |||
| 66c6152cd2 | |||
| 32cd51d3a5 | |||
| 497a28401e | |||
| e46912047c | |||
| 56b573ede5 | |||
| 0276be1789 | |||
| 7db4c60fc3 | |||
| 95cc01dd91 | |||
| cce1dddf42 | |||
| 0938b57841 | |||
| aef8550e2f | |||
| 71bf0bde32 | |||
| 750623b9b1 | |||
| 1f12c53b65 | |||
| 8717ea1b95 |
@@ -1,7 +1,9 @@
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
benchmarks/graphs
|
||||
+17
-14
@@ -1,15 +1,18 @@
|
||||
[submodule "lib/support/ext"]
|
||||
path = lib/support/ext
|
||||
url = git://github.com/visionmedia/ext.js.git
|
||||
[submodule "lib/support/sass"]
|
||||
path = lib/support/sass
|
||||
url = git://github.com/visionmedia/sass.js.git
|
||||
[submodule "lib/support/class"]
|
||||
path = lib/support/class
|
||||
url = git://github.com/visionmedia/class.js.git
|
||||
[submodule "lib/support/haml"]
|
||||
path = lib/support/haml
|
||||
[submodule "support/expresso"]
|
||||
path = support/expresso
|
||||
url = git://github.com/visionmedia/expresso.git
|
||||
[submodule "support/jade"]
|
||||
path = support/jade
|
||||
url = git://github.com/visionmedia/jade.git
|
||||
[submodule "support/haml"]
|
||||
path = support/haml
|
||||
url = git://github.com/visionmedia/haml.js.git
|
||||
[submodule "lib/support/multipart"]
|
||||
path = lib/support/multipart
|
||||
url = git://github.com/isaacs/multipart-js.git
|
||||
[submodule "support/ejs"]
|
||||
path = support/ejs
|
||||
url = http://github.com/visionmedia/ejs.git
|
||||
[submodule "support/connect-form"]
|
||||
path = support/connect-form
|
||||
url = http://github.com/visionmedia/connect-form.git
|
||||
[submodule "support/connect"]
|
||||
path = support/connect
|
||||
url = http://github.com/senchalabs/connect.git
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
- !ruby/object:Pomo::Task
|
||||
complete: false
|
||||
description:
|
||||
length: 25
|
||||
name: TM bundle
|
||||
- !ruby/object:Pomo::Task
|
||||
complete: false
|
||||
description:
|
||||
length: 25
|
||||
name: blog
|
||||
- !ruby/object:Pomo::Task
|
||||
complete: false
|
||||
description:
|
||||
length: 25
|
||||
name: release on nodejs group
|
||||
- !ruby/object:Pomo::Task
|
||||
complete: false
|
||||
description:
|
||||
length: 25
|
||||
name: Beta
|
||||
@@ -1,4 +1,23 @@
|
||||
|
||||
1.0.0beta / 2010-07-15
|
||||
==================
|
||||
|
||||
* Re-write
|
||||
- much faster
|
||||
- much lighter
|
||||
- Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs
|
||||
|
||||
0.14.0 / 2010-06-15
|
||||
==================
|
||||
|
||||
* Utilize relative requires
|
||||
* Added Static bufferSize option [aheckmann]
|
||||
* Fixed caching of view and partial subdirectories [aheckmann]
|
||||
* Fixed mime.type() comments now that ".ext" is not supported
|
||||
* Updated haml submodule
|
||||
* Updated class submodule
|
||||
* Removed bin/express
|
||||
|
||||
0.13.0 / 2010-06-01
|
||||
==================
|
||||
|
||||
|
||||
+61
-35
@@ -1,46 +1,72 @@
|
||||
|
||||
AB = ab
|
||||
ABFLAGS = -n 3000 -c 50
|
||||
NODE = node
|
||||
COFFEE = coffee
|
||||
|
||||
PREFIX = /usr/local
|
||||
LIB_PREFIX = ~/.node_libraries
|
||||
|
||||
all: test
|
||||
|
||||
install: bin/express
|
||||
ln -fs $< $(PREFIX)/bin/express
|
||||
DOCS = docs/index.md \
|
||||
docs/executable.md \
|
||||
docs/contrib.md \
|
||||
docs/guide.md \
|
||||
docs/migrate.md
|
||||
|
||||
uninstall:
|
||||
MANPAGES =$(DOCS:.md=.1)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
|
||||
install: install-docs
|
||||
@mkdir -p $(PREFIX)/bin
|
||||
cp -f bin/express $(PREFIX)/bin/express
|
||||
cp -fr lib/express $(LIB_PREFIX)/express
|
||||
|
||||
uninstall: uninstall-docs
|
||||
rm -f $(PREFIX)/bin/express
|
||||
rm -fr $(LIB_PREFIX)/express
|
||||
|
||||
install-support:
|
||||
cd support/connect && $(MAKE) install
|
||||
cd support/jade && $(MAKE) install
|
||||
|
||||
uninstall-support:
|
||||
cd support/connect && $(MAKE) uninstall
|
||||
cd support/jade && $(MAKE) uninstall
|
||||
|
||||
install-docs:
|
||||
cp -f docs/executable.1 $(PREFIX)/share/man/man1/express.1
|
||||
|
||||
uninstall-docs:
|
||||
rm -f $(PREFIX)/share/man/man1/express.1
|
||||
|
||||
test:
|
||||
@$(NODE) spec/node.js all
|
||||
|
||||
app: app-chat
|
||||
|
||||
prof:
|
||||
@$(NODE) --prof --prof_auto examples/chat/app.js
|
||||
|
||||
app-chat:
|
||||
@$(NODE) examples/chat/app.js
|
||||
@CONNECT_ENV=test ./support/expresso/bin/expresso \
|
||||
-I lib \
|
||||
-I support/connect/lib \
|
||||
-I support/haml/lib \
|
||||
-I support/jade/lib \
|
||||
-I support/ejs/lib \
|
||||
$(TESTFLAGS) \
|
||||
test/*.test.js
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
|
||||
app-hello-world:
|
||||
@$(NODE) examples/hello-world/app.js
|
||||
docs: docs/api.html $(MANPAGES) $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
|
||||
app-upload:
|
||||
@$(NODE) examples/upload/app.js
|
||||
|
||||
app-coffee-upload: compile-coffee
|
||||
@$(NODE) examples/coffee-upload/app.js
|
||||
|
||||
compile-coffee:
|
||||
@$(COFFEE) examples/coffee-upload/app.coffee
|
||||
docs/api.html: lib/express/*.js
|
||||
dox --title Express \
|
||||
--desc "High performance web framework for [node](http://nodejs.org)." \
|
||||
$(shell find lib/express/* -type f) > $@
|
||||
|
||||
benchmark: benchmarks/run
|
||||
@./benchmarks/run
|
||||
@./benchmarks/graph
|
||||
%.1: %.md
|
||||
@echo "... $< -> $@"
|
||||
@ronn -r --pipe $< > $@
|
||||
|
||||
graphs:
|
||||
@./benchmarks/graph
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@ronn -5 --pipe --fragment $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
| sed 's/NAME/Express/g' \
|
||||
> $@
|
||||
|
||||
.PHONY: install test app benchmark graphs
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: install uninstall install-docs install-support uninstall-support install-docs uninstall-docs test test-cov docs docclean
|
||||
+63
-89
@@ -2,115 +2,89 @@
|
||||
# Express
|
||||
|
||||
Insanely fast (and small) server-side JavaScript web development framework
|
||||
built on **node.js** and the **V8 JavaScript engine**.
|
||||
|
||||
* Visit the [Wiki](http://wiki.github.com/visionmedia/express) for documentation
|
||||
* Visit the [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
|
||||
## Features (so far)
|
||||
|
||||
* Sexy DSL with robust sinatra-like routing
|
||||
* High performance
|
||||
* Session support
|
||||
* Cache API
|
||||
* RESTful HTTP client
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Redirection helpers
|
||||
* Multipart file upload support
|
||||
* Test helpers (mock requests etc)
|
||||
* Environment based configuration
|
||||
* Light-weight JavaScript class implementation via [class.js](http://github.com/visionmedia/class.js/)
|
||||
* Persistent flash messages
|
||||
* Route passing
|
||||
* View support (ejs, haml, sass, etc)
|
||||
* View partials
|
||||
* View globals/helpers support
|
||||
* Full test coverage
|
||||
* Logger plugin with several formats
|
||||
* Upload size restrictions
|
||||
* Extremely readable specs
|
||||
* Cookie support
|
||||
built on [node](http://nodejs.org) and [Connect](http://github.com/extjs/Connect).
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Installation
|
||||
|
||||
Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
|
||||
and run:
|
||||
|
||||
$ kiwi -v install express
|
||||
|
||||
or
|
||||
npm:
|
||||
|
||||
Install via git clone:
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git && cd express && git submodule update --init
|
||||
$ npm install connect
|
||||
$ npm install express
|
||||
|
||||
## Examples
|
||||
curl (or similar):
|
||||
|
||||
Below is a tiny Express application. View the [Wiki](http://wiki.github.com/visionmedia/express/) for detailed information.
|
||||
$ curl -# http://github.com/visionmedia/express/raw/master/install.sh | sh
|
||||
|
||||
require.paths.unshift('express/lib')
|
||||
require('express')
|
||||
|
||||
configure(function(){
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/user', function(){
|
||||
this.redirect('/user/' + this.currentUser.id)
|
||||
})
|
||||
|
||||
get('/user/:id', function(id){
|
||||
this.render('user.haml.html', {
|
||||
locals: {
|
||||
user: this.currentUser,
|
||||
usersOnline: Session.store.length()
|
||||
}
|
||||
})
|
||||
})
|
||||
git clone, first update the submodules:
|
||||
|
||||
$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://extjs.github.com/Connect)
|
||||
* Executable for generating applications quickly
|
||||
|
||||
Via Connect:
|
||||
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
## Contributors
|
||||
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
|
||||
## More Information
|
||||
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* [JavaScript Extensions & Utilities](http://github.com/visionmedia/ext.js)
|
||||
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
|
||||
* [JavaScript Haml](http://github.com/visionmedia/haml.js)
|
||||
* [JavaScript Jade](http://github.com/visionmedia/jade) spiritual successor of Haml
|
||||
|
||||
run()
|
||||
|
||||
## Running Tests
|
||||
|
||||
Express uses the [JSpec](http://jspec.info) BDD JavaScript testing
|
||||
framework to write and run elegant spec suites. JSpec is frozen
|
||||
to spec/lib and **does not** require separate installation.
|
||||
Express uses the [Expresso](http://github.com/visionmedia/expresso) TDD
|
||||
framework to write and run elegant test suites extremely fast. First `$ git submodule update --init`, then run:
|
||||
|
||||
$ make test
|
||||
|
||||
Run individual suites:
|
||||
|
||||
$ node spec/node.js core
|
||||
$ node spec/node.js mime
|
||||
$ node spec/node.js routing
|
||||
...
|
||||
|
||||
The latest release of Express is compatible with node --version:
|
||||
v0.1.97
|
||||
|
||||
With _EDGE_ Express we do our best to keep up to date with node's _EDGE_
|
||||
|
||||
## More Information
|
||||
|
||||
* [JavaScript Extensions & Utilities](http://github.com/visionmedia/ext.js)
|
||||
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
|
||||
* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4
|
||||
* [0.9.0 release details](http://tjholowaychuk.com/post/522036176/express-0-9-0-released)
|
||||
* [Express vs Sinatra Benchmarks](http://tjholowaychuk.com/post/543953703/express-vs-sinatra-benchmarks)
|
||||
|
||||
## Contributors
|
||||
|
||||
* TJ Holowaychuk (visionmedia) <tj@vision-media.ca>
|
||||
* Aaron Heckmann (aheckmann) <aaron.heckmann+github@gmail.com>
|
||||
* Ciaran Jessup (ciaranj) <ciaranj@gmail.com>
|
||||
* Gareth Jones (csausdev) <gareth.jones@sensis.com.au>
|
||||
v0.1.100
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
//enable('cache view contents')
|
||||
set('root', __dirname)
|
||||
set('views', __dirname + '/../shared')
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.render('page.html.haml')
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
//enable('cache view contents')
|
||||
set('root', __dirname)
|
||||
set('views', __dirname + '/../shared')
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.render('style.css.sass', { layout: false })
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
|
||||
get('/', function(){
|
||||
return 'Hello World'
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
use(Static)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.sendfile('benchmarks/shared/jquery.js', { bufferSize: 8 * 1024 })
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
use(Static)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.sendfile('benchmarks/shared/huge.js', { bufferSize: 8 * 1024 })
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
COL=${COL-9}
|
||||
|
||||
#
|
||||
# Log <msg ...>
|
||||
#
|
||||
# <msg ...>
|
||||
#
|
||||
|
||||
log(){
|
||||
echo "... $@"
|
||||
}
|
||||
|
||||
#
|
||||
# Output gnuplot script for line graph.
|
||||
#
|
||||
# <title> <node> <express> <sinatra>
|
||||
#
|
||||
|
||||
function line() {
|
||||
cat <<-EOF
|
||||
set terminal png
|
||||
set output "benchmarks/graphs/$1.png"
|
||||
set title "$1"
|
||||
set size 1,0.7
|
||||
set grid y
|
||||
set key left top
|
||||
set xlabel "request"
|
||||
set ylabel "response time (ms)"
|
||||
plot "benchmarks/$2" using $COL smooth sbezier with lines title "node", \\
|
||||
"benchmarks/$3" using $COL smooth sbezier with lines title "express", \\
|
||||
"benchmarks/$4" using $COL smooth sbezier with lines title "sinatra thin"
|
||||
EOF
|
||||
}
|
||||
|
||||
#
|
||||
# Output gnuplot script for bar graph.
|
||||
#
|
||||
# <title> <node> <express> <sinatra>
|
||||
#
|
||||
|
||||
function bar() {
|
||||
cat <<-EOF
|
||||
set terminal png
|
||||
set output "benchmarks/graphs/$1.rps.png"
|
||||
set title "$1"
|
||||
set size 0.7,0.5
|
||||
set grid y
|
||||
set key left top
|
||||
set ylabel "requests per second"
|
||||
plot "benchmarks/$1.rps.dat" using 2: xtic(1) with histogram title ""
|
||||
EOF
|
||||
}
|
||||
|
||||
mkdir -p benchmarks/graphs
|
||||
|
||||
for type in simple haml sass static static.large; do
|
||||
plot=benchmarks/graphs/$type.p
|
||||
log generating benchmarks/graphs/$type.png
|
||||
line $type \
|
||||
node/$type.js.dat \
|
||||
express/$type.js.dat \
|
||||
thin/$type.ru.dat \
|
||||
> $plot
|
||||
gnuplot $plot
|
||||
|
||||
log generating benchmarks/graphs/$type.rps.png
|
||||
plot=benchmarks/graphs/$type.rps.p
|
||||
dat=benchmarks/$type.rps.dat
|
||||
:> $dat
|
||||
for server in node express thin; do
|
||||
case $server in
|
||||
node|express) ext=js ;;
|
||||
thin) ext=ru ;;
|
||||
esac
|
||||
rps=$(cat benchmarks/$server/$type.$ext.out | grep "Requests per second:" | awk '{ print $4 }')
|
||||
echo $server $rps >> $dat
|
||||
done
|
||||
bar $type > $plot
|
||||
gnuplot $plot
|
||||
done
|
||||
|
||||
rm benchmarks/graphs/*.p
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
var fs = require('fs'),
|
||||
http = require('http')
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': 11 })
|
||||
res.end('Hello World', 'ascii')
|
||||
}).listen(3000, 'localhost')
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
var fs = require('fs'),
|
||||
http = require('http')
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked' })
|
||||
fs.createReadStream('benchmarks/shared/jquery.js')
|
||||
.addListener('data', function(data){
|
||||
res.write(data, 'binary')
|
||||
})
|
||||
.addListener('end', function(){
|
||||
res.end()
|
||||
})
|
||||
}).listen(3000, 'localhost')
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
var fs = require('fs'),
|
||||
http = require('http')
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked' })
|
||||
fs.createReadStream('benchmarks/shared/huge.js')
|
||||
.addListener('data', function(data){
|
||||
res.write(data, 'binary')
|
||||
})
|
||||
.addListener('end', function(){
|
||||
res.end()
|
||||
})
|
||||
}).listen(3000, 'localhost')
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SLEEP=${SLEEP-2}
|
||||
ABFLAGS=${ABFLAGS-"-n 2000 -c 50"}
|
||||
ADDR=${ADDR-http://127.0.0.1:3000/}
|
||||
AB=${AB-ab}
|
||||
|
||||
#
|
||||
# Log <msg ...>
|
||||
#
|
||||
# <msg ...>
|
||||
#
|
||||
|
||||
log(){
|
||||
echo "... $@"
|
||||
}
|
||||
|
||||
#
|
||||
# Benchmark <type> and <file>
|
||||
#
|
||||
# - starts the server
|
||||
# - allows $SLEEP seconds for startup
|
||||
# - runs $AB
|
||||
# - kills the server process
|
||||
#
|
||||
# <type> <file>
|
||||
#
|
||||
|
||||
bm(){
|
||||
local type=$1
|
||||
local file=$2
|
||||
log benchmarking $type $file
|
||||
case $type in
|
||||
node|express)
|
||||
node benchmarks/$type/$file &
|
||||
;;
|
||||
thin)
|
||||
thin -R benchmarks/thin/$file -p 3000 start &
|
||||
;;
|
||||
esac
|
||||
pid=$!
|
||||
sleep $SLEEP
|
||||
$AB $ABFLAGS -g benchmarks/$type/$file.dat $ADDR > benchmarks/$type/$file.out
|
||||
log $(cat benchmarks/$type/$file.out | grep Requests)
|
||||
kill -KILL $pid
|
||||
}
|
||||
|
||||
log ab $ABFLAGS $ADDR
|
||||
bm node simple.js
|
||||
bm node static.js
|
||||
bm node static.large.js
|
||||
bm express simple.js
|
||||
bm express static.js
|
||||
bm express static.large.js
|
||||
bm express haml.js
|
||||
bm express sass.js
|
||||
bm thin simple.ru
|
||||
bm thin static.ru
|
||||
bm thin static.large.ru
|
||||
bm thin haml.ru
|
||||
bm thin sass.ru
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
-19
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,6 +0,0 @@
|
||||
!!!
|
||||
%html
|
||||
%head
|
||||
%title Wahoo
|
||||
%body
|
||||
#primary= yield
|
||||
@@ -1,6 +0,0 @@
|
||||
!!!
|
||||
%html
|
||||
%head
|
||||
%title Wahoo
|
||||
%body
|
||||
#primary!= body
|
||||
@@ -1,10 +0,0 @@
|
||||
%h1 Some title
|
||||
%ul
|
||||
%li a
|
||||
%li b
|
||||
%li c
|
||||
%li
|
||||
%ol
|
||||
%li d
|
||||
%li e
|
||||
%li f
|
||||
@@ -1,10 +0,0 @@
|
||||
%h1 Some title
|
||||
%ul
|
||||
%li a
|
||||
%li b
|
||||
%li c
|
||||
%li
|
||||
%ol
|
||||
%li d
|
||||
%li e
|
||||
%li f
|
||||
@@ -1,73 +0,0 @@
|
||||
body
|
||||
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
|
||||
:font-size 13px
|
||||
:text-align center
|
||||
:color #555
|
||||
|
||||
h1, h2
|
||||
:margin 0
|
||||
:font-size 22px
|
||||
:color #343434
|
||||
h1
|
||||
:text-shadow 1px 2px 2px #ddd
|
||||
:font-size 60px
|
||||
|
||||
img.bubble
|
||||
:position absolute
|
||||
:top -25px
|
||||
:left 120px
|
||||
|
||||
#wrapper
|
||||
:position relative
|
||||
:margin 100px auto
|
||||
:width 500px
|
||||
:text-align left
|
||||
|
||||
ul
|
||||
:margin 0
|
||||
:padding 0
|
||||
:max-height 300px
|
||||
:overflow-x hidden
|
||||
li
|
||||
:margin 5px 0
|
||||
:padding 3px 8px
|
||||
:list-style none
|
||||
:border 1px solid #eee
|
||||
li:hover
|
||||
:cursor pointer
|
||||
:color #2E2E2E
|
||||
|
||||
input[type=text]
|
||||
:padding 5px
|
||||
:border 1px solid #ddd
|
||||
:outline none
|
||||
input[type=text]:focus
|
||||
:border-color #00C3FF
|
||||
|
||||
input[type=submit]
|
||||
:padding 6px 10px
|
||||
:border solid 1px #999
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
|
||||
:color #333
|
||||
:text-decoration none
|
||||
:cursor pointer
|
||||
:display inline-block
|
||||
:text-align center
|
||||
:text-shadow 0px 1px 1px #fff
|
||||
:line-height 1
|
||||
input[type=submit]:hover
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
|
||||
input[type=submit]:active
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
|
||||
input[name=name]
|
||||
:width 80px
|
||||
|
||||
a
|
||||
:color #1ABFF1
|
||||
a:hover
|
||||
:padding 0 5px
|
||||
a:hover:before
|
||||
:content 'visit: '
|
||||
|
||||
#online
|
||||
:font-size 12px
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'haml'
|
||||
|
||||
configure do
|
||||
set 'views', File.dirname(__FILE__) + '/../shared'
|
||||
end
|
||||
|
||||
get '/' do
|
||||
haml :page, :ugly => true
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'sass'
|
||||
|
||||
configure do
|
||||
set 'views', File.dirname(__FILE__) + '/../shared'
|
||||
end
|
||||
|
||||
get '/' do
|
||||
sass :'style.css'
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
|
||||
get '/' do
|
||||
'Hello World'
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
|
||||
get '/' do
|
||||
send_file 'benchmarks/shared/huge.js'
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
|
||||
get '/' do
|
||||
send_file 'benchmarks/shared/jquery.js'
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
+172
-131
@@ -1,142 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env node
|
||||
|
||||
#
|
||||
# Output usage information and exit.
|
||||
#
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
function usage() {
|
||||
echo 'usage: express [options] [dir]'
|
||||
exit 1
|
||||
var sys = require('sys'),
|
||||
fs = require('fs'),
|
||||
childProcess = require('child_process');
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '1.0.0beta';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\x1b[1mUsage\x1b[0m: express [options] [PATH]\n'
|
||||
+ '\n'
|
||||
+ '\x1b[1mOptions\x1b[0m:\n'
|
||||
+ ' -v, --version Output framework version\n'
|
||||
+ ' -h, --help Output help information\n';
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'!!!',
|
||||
'html',
|
||||
' head',
|
||||
' title= title',
|
||||
' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')',
|
||||
' body!= body'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default sass template.
|
||||
*/
|
||||
|
||||
var sass = [
|
||||
'body',
|
||||
' :padding 50px',
|
||||
' :font 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'h1= title',
|
||||
'p Welcome to #{title}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* App template.
|
||||
*/
|
||||
|
||||
var app = [
|
||||
'',
|
||||
'/**',
|
||||
' * Module dependencies.',
|
||||
' */',
|
||||
'',
|
||||
'var express = require(\'express\'),',
|
||||
' connect = require(\'connect\');',
|
||||
'',
|
||||
'// Create and export Express app',
|
||||
'',
|
||||
'var app = express.createServer();',
|
||||
'',
|
||||
'// Configuration',
|
||||
'',
|
||||
'app.configure(function(){',
|
||||
' app.set(\'views\', __dirname + \'/views\');',
|
||||
' app.use(\'/\', connect.bodyDecoder());',
|
||||
' app.use(\'/\', connect.methodOverride());',
|
||||
' app.use(\'/\', connect.compiler({ src: __dirname + \'/public\', enable: [\'sass\'] }));',
|
||||
' app.use(\'/\', connect.staticProvider(__dirname + \'/public\'));',
|
||||
'});',
|
||||
'',
|
||||
'app.configure(\'development\', function(){',
|
||||
' app.set(\'reload views\', 1000);',
|
||||
' app.use(\'/\', connect.errorHandler({ dumpExceptions: true, showStack: true })); ',
|
||||
'});',
|
||||
'',
|
||||
'app.configure(\'production\', function(){',
|
||||
' app.use(\'/\', connect.errorHandler()); ',
|
||||
'});',
|
||||
'',
|
||||
'// Routes',
|
||||
'',
|
||||
'app.get(\'/\', function(req, res){',
|
||||
' res.render(\'index.jade\', {',
|
||||
' locals: {',
|
||||
' title: \'Express\'',
|
||||
' }',
|
||||
' });',
|
||||
'});',
|
||||
'',
|
||||
'app.listen(3000);',
|
||||
''
|
||||
].join('\n');
|
||||
|
||||
// Parse arguments
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
path = '.';
|
||||
while (args.length) {
|
||||
var arg = args.shift();
|
||||
switch (arg) {
|
||||
case '-h':
|
||||
case '--help':
|
||||
abort(usage);
|
||||
break;
|
||||
case '-v':
|
||||
case '--version':
|
||||
abort(version);
|
||||
break;
|
||||
default:
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Create template in the givin [dir] or cwd.
|
||||
#
|
||||
# [dir]
|
||||
#
|
||||
// Generate application
|
||||
|
||||
function create_template() {
|
||||
local dir=${1-.}
|
||||
mkdir -p $dir
|
||||
[[ $(ls $dir) ]] && confirm "$dir is not empty, continue?"
|
||||
mkdir -p $dir/public/{javascripts,stylesheets,images}
|
||||
mkdir -p $dir/views/partials
|
||||
app_template > $dir/app.js
|
||||
layout_template > $dir/views/layout.html.haml
|
||||
front_template > $dir/views/front.html.haml
|
||||
sass_template > $dir/views/style.css.sass
|
||||
echo template created in $dir
|
||||
(function createApplication(path) {
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/pids');
|
||||
mkdir(path + '/logs');
|
||||
mkdir(path + '/public/{javascripts,stylesheets,images}', function(){
|
||||
write(path + '/public/stylesheets/style.sass', sass);
|
||||
});
|
||||
mkdir(path + '/views/partials', function(){
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
});
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
})(path);
|
||||
|
||||
/**
|
||||
* echo str > path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function write(path, str) {
|
||||
fs.writeFile(path, str);
|
||||
sys.puts(' create : ' + path);
|
||||
}
|
||||
|
||||
#
|
||||
# views/style.css.sass
|
||||
#
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function sass_template() {
|
||||
cat <<-EOF
|
||||
blue: #03ADF0
|
||||
light: #4d4d4d
|
||||
lighter: #eee
|
||||
|
||||
body
|
||||
:margin 80px
|
||||
:font 14px/1.5 "Helvetica Nueue", "Lucida Grande", "Arial", sans-serif
|
||||
|
||||
code
|
||||
:padding 3px 10px
|
||||
:border 1px solid !lighter
|
||||
:color !light
|
||||
|
||||
a
|
||||
:color !blue
|
||||
:text-decoration none
|
||||
&:hover
|
||||
:text-decoration underline
|
||||
EOF
|
||||
function mkdir(path, fn) {
|
||||
childProcess.exec('mkdir -p ' + path, function(err){
|
||||
if (err) throw err;
|
||||
sys.puts(' create : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
#
|
||||
# views/front.html.haml
|
||||
#
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function front_template() {
|
||||
cat <<-EOF
|
||||
%h1 Express
|
||||
%p
|
||||
Generated by the
|
||||
<code>express</code>
|
||||
executable.
|
||||
%p
|
||||
Visit
|
||||
%a{ href: 'http://expressjs.com' } ExpressJS.com
|
||||
for more information.
|
||||
EOF
|
||||
}
|
||||
|
||||
#
|
||||
# views/layout.html.haml
|
||||
#
|
||||
|
||||
function layout_template() {
|
||||
cat <<-EOF
|
||||
!!! strict
|
||||
%html
|
||||
%head
|
||||
%title Express
|
||||
%link{ rel: 'stylesheet', href: 'style.css' }
|
||||
%body!= body
|
||||
EOF
|
||||
}
|
||||
|
||||
#
|
||||
# app.js
|
||||
#
|
||||
|
||||
function app_template() {
|
||||
cat <<-EOF
|
||||
// If you are using the kiwi package manager
|
||||
var kiwi = require('kiwi'),
|
||||
express = kiwi.require('express')
|
||||
|
||||
// Otherwise you will need to expose the path to express
|
||||
// require.paths.unshift('path/to/express/lib')
|
||||
// require('express')
|
||||
|
||||
configure(function(){
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.render('front.html.haml')
|
||||
})
|
||||
|
||||
get('/*.css', function(path){
|
||||
this.render(path + '.css.sass', { layout: false })
|
||||
})
|
||||
|
||||
run()
|
||||
EOF
|
||||
}
|
||||
|
||||
#
|
||||
# Confirm <msg> or exit.
|
||||
#
|
||||
# <msg>
|
||||
#
|
||||
|
||||
function confirm() {
|
||||
echo -n "$1 "
|
||||
read answer
|
||||
case $answer in
|
||||
n|N|no) exit 1 ;;
|
||||
y|Y|yes) ;;
|
||||
*) confirm "yes or no?" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Process arguments
|
||||
|
||||
case $1 in
|
||||
-h|--help|help) usage ;;
|
||||
*) create_template $1 ;;
|
||||
esac
|
||||
function abort(str) {
|
||||
sys.error(str);
|
||||
process.exit(1);
|
||||
}
|
||||
+1032
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,64 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "CONTRIB" "" "July 2010" "" ""
|
||||
.
|
||||
.SS "Development Dependencies"
|
||||
Express development dependencies are stored within the \fI\./support\fR directory\. To update them execute:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ git submodule update \-\-init
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Running Tests"
|
||||
Express uses the Expresso \fIhttp://github\.com/visionmedia/expresso\fR TDD framework to write and run elegant test suites extremely fast\. To run all test suites simply execute:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ make test
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To target specific suites we may specify the files via:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ make test TESTS=test/view\.test\.js
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Contributions"
|
||||
To accept a contribution, you should follow these guidelines:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
All tests \fImust\fR pass
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Your alterations or additions \fImust\fR include tests
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Your commit(s) should be \fIfocused\fR, do not commit once for several changes
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Do \fInot\fR alter release information such as the \fIversion\fR, or \fIHistory\.md\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Indents are \fI4\fR spaces\.
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Development-Dependencies">Development Dependencies</h3>
|
||||
|
||||
<p>Express development dependencies are stored within the <em>./support</em> directory. To
|
||||
update them execute:</p>
|
||||
|
||||
<pre><code>$ git submodule update --init
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Running-Tests">Running Tests</h3>
|
||||
|
||||
<p>Express uses the <a href="http://github.com/visionmedia/expresso">Expresso</a> TDD
|
||||
framework to write and run elegant test suites extremely fast. To run all test suites
|
||||
simply execute:</p>
|
||||
|
||||
<pre><code>$ make test
|
||||
</code></pre>
|
||||
|
||||
<p>To target specific suites we may specify the files via:</p>
|
||||
|
||||
<pre><code>$ make test TESTS=test/view.test.js
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Contributions">Contributions</h3>
|
||||
|
||||
<p>To accept a contribution, you should follow these guidelines:</p>
|
||||
|
||||
<ul>
|
||||
<li>All tests <em>must</em> pass</li>
|
||||
<li>Your alterations or additions <em>must</em> include tests</li>
|
||||
<li>Your commit(s) should be <em>focused</em>, do not commit once for several changes</li>
|
||||
<li>Do <em>not</em> alter release information such as the <em>version</em>, or <em>History.md</em></li>
|
||||
<li>Indents are <em>4</em> spaces.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
Express development dependencies are stored within the _./support_ directory. To
|
||||
update them execute:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
### Running Tests
|
||||
|
||||
Express uses the [Expresso](http://github.com/visionmedia/expresso) TDD
|
||||
framework to write and run elegant test suites extremely fast. To run all test suites
|
||||
simply execute:
|
||||
|
||||
$ make test
|
||||
|
||||
To target specific suites we may specify the files via:
|
||||
|
||||
$ make test TESTS=test/view.test.js
|
||||
|
||||
### Contributions
|
||||
|
||||
To accept a contribution, you should follow these guidelines:
|
||||
|
||||
* All tests _must_ pass
|
||||
* Your alterations or additions _must_ include tests
|
||||
* Your commit(s) should be _focused_, do not commit once for several changes
|
||||
* Do _not_ alter release information such as the _version_, or _History.md_
|
||||
* Indents are _4_ spaces.
|
||||
@@ -0,0 +1,25 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "EXECUTABLE" "" "July 2010" "" ""
|
||||
.
|
||||
.SH "Synopsis"
|
||||
.
|
||||
.nf
|
||||
|
||||
express [\-h|\-\-help] [\-v|\-\-version] [PATH]
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.SH "Description"
|
||||
The \fBexpress\fR executable generates apps at the given \fBPATH\fR or the current working directory\. Although Express is not bound to a specific application structure, this executable creates a maintainable base app\.
|
||||
.
|
||||
.SH "Options"
|
||||
.
|
||||
.nf
|
||||
|
||||
\-v, \-\-version Output framework version
|
||||
\-h, \-\-help Display help information
|
||||
.
|
||||
.fi
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h2 id="Synopsis">Synopsis</h2>
|
||||
|
||||
<pre><code>express [-h|--help] [-v|--version] [PATH]
|
||||
</code></pre>
|
||||
|
||||
<h2 id="Description">Description</h2>
|
||||
|
||||
<p>The <code>express</code> executable generates apps at the given <strong>PATH</strong> or the
|
||||
current working directory. Although Express is not bound to a specific
|
||||
application structure, this executable creates a maintainable base app.</p>
|
||||
|
||||
<h2 id="Options">Options</h2>
|
||||
|
||||
<pre><code>-v, --version Output framework version
|
||||
-h, --help Display help information
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
## Synopsis
|
||||
|
||||
express [-h|--help] [-v|--version] [PATH]
|
||||
|
||||
## Description
|
||||
|
||||
The `express` executable generates apps at the given **PATH** or the
|
||||
current working directory. Although Express is not bound to a specific
|
||||
application structure, this executable creates a maintainable base app.
|
||||
|
||||
## Options
|
||||
|
||||
-v, --version Output framework version
|
||||
-h, --help Display help information
|
||||
|
||||
+860
@@ -0,0 +1,860 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "GUIDE" "" "July 2010" "" ""
|
||||
.
|
||||
.SS "Installation"
|
||||
npm:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ npm install connect
|
||||
$ npm install express
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
curl (or similar):
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ curl \-# http://github\.com/visionmedia/express/raw/master/install\.sh | sh
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
git clone, first update the submodules:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ git submodule update \-\-init
|
||||
$ make install
|
||||
$ make install\-support
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Creating An Application"
|
||||
The \fIexpress\.Server\fR now inherits from \fIhttp\.Server\fR, however follows the same idiom by providing \fIexpress\.createServer()\fR as shown below\. This means that you can utilize Express server\'s transparently with other libraries\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var app = require(\'express\')\.createServer();
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.send(\'hello world\');
|
||||
});
|
||||
|
||||
app\.listen(3000);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Configuration"
|
||||
Express supports arbitrary environments, such as \fIproduction\fR and \fIdevelopment\fR\. Developers can use the \fIconfigure()\fR method to setup needs required by the current environment\. When \fIconfigure()\fR is called without an environment name it will be run in \fIevery\fR environment prior to the environment specific callback\.
|
||||
.
|
||||
.P
|
||||
In the example below we only \fIdumpExceptions\fR, and respond with exception stack traces in \fIdevelopment\fR mode, however for both environments we utilize \fImethodOverride\fR and \fIbodyDecoder\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.configure(function(){
|
||||
app\.use(\'/\', connect\.methodOverride());
|
||||
app\.use(\'/\', connect\.bodyDecoder());
|
||||
});
|
||||
|
||||
app\.configure(\'development\', function(){
|
||||
app\.use(\'/\', connect\.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
app\.configure(\'production\', function(){
|
||||
app\.use(\'/\', connect\.errorHandler());
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
For internal and arbitrary settings Express provides the \fIset(key[, val])\fR, \fIenable(key)\fR, \fIdisable(key)\fR methods:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.configure(function(){
|
||||
app\.set(\'views\', __dirname + \'/views\');
|
||||
app\.set(\'views\');
|
||||
// => \"\.\.\. views directory \.\.\.\"
|
||||
|
||||
app\.enable(\'some feature\');
|
||||
// same as app\.set(\'some feature\', true);
|
||||
|
||||
app\.disable(\'some feature\');
|
||||
// same as app\.set(\'some feature\', false);
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To alter the environment we can set the \fICONNECT_ENV\fR environment variable, or more specifically \fIEXPRESS_ENV\fR, for example:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ EXPRESS_ENV=production node app\.js
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Settings"
|
||||
Express supports the following settings out of the box:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fIenv\fR Application environment set internally, use \fIapp\.set(\'env\')\fR to utilize
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fIhome\fR Application base path used with \fIres\.redirect()\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fIviews\fR Root views directory defaulting to \fBCWD/views\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fIview engine\fR Default view engine name for views rendered without extensions
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fIreload views\fR Reloads altered views, by default watches for \fImtime\fR changes with with a 5 minute interval\. Example: \fIapp\.set(\'reload views\', 60000);\fR
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Routing"
|
||||
Express utilizes the HTTP verbs to provide a meaningful, expressive routing API\. For example we may want to render a user\'s account for the path \fI/user/12\fR, this can be done by defining the route below\. The values associated to the named placeholders, are passed as the \fIthird\fR argument, which here we name \fIparams\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id\', function(req, res, params){
|
||||
res\.send(\'user \' + params\.id);
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
A route is simple a string which is compiled to a \fIRegExp\fR internally\. For example when \fI/user/:id\fR is compiled, a simplified version of the regexp may look similar to:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
\\/user\\/([^\\/]+)\\/?
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Literal regular expressions may also be passed for complex uses:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(/^\\/foo(bar)?$/, function(){});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Below are some route examples, and the associated paths that they may consume:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
\"/user/:id\"
|
||||
/user/12
|
||||
|
||||
\"/users/:id?\"
|
||||
/users/5
|
||||
/users
|
||||
|
||||
\"/files/*\"
|
||||
/files/jquery\.js
|
||||
/files/javascripts/jquery\.js
|
||||
|
||||
\"/file/*\.*\"
|
||||
/files/jquery\.js
|
||||
/files/javascripts/jquery\.js
|
||||
|
||||
\"/user/:id/:operation?\"
|
||||
/user/1
|
||||
/user/1/edit
|
||||
|
||||
\"/products\.:format\"
|
||||
/products\.json
|
||||
/products\.xml
|
||||
|
||||
\"/products\.:format?\"
|
||||
/products\.json
|
||||
/products\.xml
|
||||
/products
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Passing Route Control"
|
||||
We may pass control to the next \fImatching\fR route, by calling the \fIfourth\fR parameter, the \fInext()\fR function\. When a match cannot be made, control is passed back to Connect\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/users/:id?\', function(req, res, params){
|
||||
if (params\.id) {
|
||||
// do something
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app\.get(\'/users\', function(req, res, params){
|
||||
// do something else
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Middleware"
|
||||
The Express \fIPlugin\fR is no more! middleware via Connect \fIhttp://github\.com/extjs/Connect\fR can be passed to \fIexpress\.createServer()\fR as you would with a regular Connect server\. For example:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var connect = require(\'connect\'),
|
||||
express = require(\'express\');
|
||||
|
||||
var app = express\.createServer(
|
||||
connect\.logger(),
|
||||
connect\.bodyDecoder()
|
||||
);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Alternatively we can \fIuse()\fR them which is useful when adding middleware within \fIconfigure()\fR blocks:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.use(\'/\', connect\.logger({ format: \':method :uri\' }));
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Error Handling"
|
||||
Express provides the \fIapp\.error()\fR method which receives exceptions thrown within a route, or passed to \fInext(err)\fR\. Below is an example which serves different pages based on our ad\-hoc \fINotFound\fR exception:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
function NotFound(msg){
|
||||
this\.name = \'NotFound\';
|
||||
Error\.call(this, msg);
|
||||
Error\.captureStackTrace(this, arguments\.callee);
|
||||
}
|
||||
|
||||
sys\.inherits(NotFound, Error);
|
||||
|
||||
app\.get(\'/404\', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app\.get(\'/500\', function(req, res){
|
||||
throw new Error(\'keyboard cat!\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
We can call \fIapp\.error()\fR several times as shown below\. Here we check for an instanceof \fINotFound\fR and show the 404 page, or we pass on to the next error handler\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res\.render(\'404\.jade\');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Here we assume all errors as 500 for the simplicity of this demo, however you can choose whatever you like
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.error(function(err, req, res){
|
||||
res\.render(\'500\.jade\', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Our apps could also utilize the Connect \fIerrorHandler\fR middleware to report on exceptions\. For example if we wish to output exceptions in \"development\" mode to \fIstderr\fR we can use:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.use(\'/\', connect\.errorHandler({ dumpExceptions: true }));
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Also during development we may want fancy html pages to show exceptions that are passed or thrown, so we can set \fIshowStack\fR to true:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.use(\'/\', connect\.errorHandler({ showStack: true, dumpExceptions: true }));
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
The \fIerrorHandler\fR middleware also responds with \fIjson\fR if \fIAccept: application/json\fR is present, which is useful for developing apps that rely heavily on client\-side JavaScript\.
|
||||
.
|
||||
.SS "View Rendering"
|
||||
View filenames take the form \fINAME\fR\.\fIENGINE\fR, where \fIENGINE\fR is the name of the module that will be required\. For example the view \fIlayout\.ejs\fR will tell the view system to \fIrequire(\'ejs\')\fR, the module being loaded must (currently) export the method \fIexports\.render(str, options)\fR to comply with Express, however with will likely be extensible in the future\.
|
||||
.
|
||||
.P
|
||||
Below is an example using Haml\.js \fIhttp://github\.com/visionmedia/haml\.js\fR to render \fIindex\.html\fR, and since we do not use \fIlayout: false\fR the rendered contents of \fIindex\.html\fR will be passed as the \fIbody\fR local variable in \fIlayout\.haml\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.render(\'index\.haml\', {
|
||||
locals: { title: \'My Site\' }
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "View Partials"
|
||||
The Express view system has built\-in support for partials and collections, which are sort of \"mini\" views representing a document fragment\. For example rather than iterating in a view to display comments, we would use a partial with collection support:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\.haml\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To make things even less verbose we can assume the extension as \fI\.haml\fR when omitted, however if we wished we could use an ejs partial, within a haml view for example\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
And once again even further, when rendering a collection we can simply pass an array, if no other options are desired:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comments\', comments);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Template Engines"
|
||||
Below are a few template engines commonly used with Express:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Jade \fIhttp://github\.com/visionmedia/jade\fR haml\.js successor
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Haml \fIhttp://github\.com/visionmedia/haml\.js\fR indented templates
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
EJS \fIhttp://github\.com/visionmedia/ejs\fR Embedded JavaScript
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "req\.header(key[, defaultValue])"
|
||||
Get the case\-insensitive request header \fIkey\fR, with optional \fIdefaultValue\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
req\.header(\'Host\');
|
||||
req\.header(\'host\');
|
||||
req\.header(\'Accept\', \'*/*\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "req\.accepts(type)"
|
||||
Check if the \fIAccept\fR header is present, and includes the given \fItype\fR\.
|
||||
.
|
||||
.P
|
||||
When the \fIAccept\fR header is not present \fItrue\fR is returned\. Otherwise the given \fItype\fR is matched by an exact match, and then subtypes\. You may pass the subtype such as \"html\" which is then converted internally to \"text/html\" using the mime lookup table\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
// Accept: text/html
|
||||
req\.accepts(\'html\');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req\.accepts(\'html\');
|
||||
req\.accepts(\'text/html\');
|
||||
req\.accepts(\'text/plain\');
|
||||
req\.accepts(\'application/json\');
|
||||
// => true
|
||||
|
||||
req\.accepts(\'image/png\');
|
||||
req\.accepts(\'png\');
|
||||
// => false
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "req\.param(name)"
|
||||
Return the value of param \fIname\fR when present\.
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Checks route placeholders, ex: /user/:id
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Checks query string params, ex: ?id=12
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Checks urlencoded body params, ex: id=12
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To utilize urlencoded request bodies, \fIreq\.body\fR should be an object\. This can be done by using the \fIconnect\.bodyDecoder\fR middleware\.
|
||||
.
|
||||
.SS "req\.flash(type[, msg])"
|
||||
Queue flash \fImsg\fR of the given \fItype\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
req\.flash(\'info\', \'email sent\');
|
||||
req\.flash(\'error\', \'email delivery failed\');
|
||||
req\.flash(\'info\', \'email re\-sent\');
|
||||
// => 2
|
||||
|
||||
req\.flash(\'info\');
|
||||
// => [\'email sent\', \'email re\-sent\']
|
||||
|
||||
req\.flash(\'info\');
|
||||
// => []
|
||||
|
||||
req\.flash();
|
||||
// => { error: [\'email delivery failed\'], info: [] }
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "req\.isXMLHttpRequest"
|
||||
Also aliased as \fIreq\.xhr\fR, this getter checks the \fIX\-Requested\-With\fR header to see if it was issued by an \fIXMLHttpRequest\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
req\.xhr
|
||||
req\.isXMLHttpRequest
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "res\.header(key[, val])"
|
||||
Get or set the response header \fIkey\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.header(\'Content\-Length\');
|
||||
// => undefined
|
||||
|
||||
res\.header(\'Content\-Length\', 123);
|
||||
// => 123
|
||||
|
||||
res\.header(\'Content\-Length\');
|
||||
// => 123
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "res\.contentType(type)"
|
||||
Sets the \fIContent\-Type\fR response header to the given \fItype\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var filename = \'path/to/image\.png\';
|
||||
res\.contentType(filename);
|
||||
// res\.headers[\'Content\-Type\'] is now \"image/png\"
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "res\.attachment([filename])"
|
||||
Sets the \fIContent\-Disposition\fR response header to \"attachment\", with optional \fIfilename\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.attachment(\'path/to/my/image\.png\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "res\.sendfile(path)"
|
||||
Used by \fBres\.download()\fR to transfer an arbitrary file\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.sendfile(\'path/to/my\.file\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
\fBNOTE\fR: this is \fInot\fR a replacement for Connect\'s \fIstaticProvider\fR middleware, nor does it perform any security checks, use with caution when using in a dynamic manor\.
|
||||
.
|
||||
.SS "res\.download(file[, filename])"
|
||||
Transfer the given \fIfile\fR as an attachment with optional alternative \fIfilename\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.download(\'path/to/image\.png\');
|
||||
res\.download(\'path/to/image\.png\', \'foo\.png\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
This is equivalent to:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.attachment(file);
|
||||
res\.sendfile(file);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "res\.send(body|status[, headers|status[, status]])"
|
||||
The \fBres\.send()\fR method is a high level response utility allowing you to pass objects to respond with json, strings for html, arbitrary _Buffer_s or numbers for status code based responses\. The following are all valid uses:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.send(new Buffer(\'wahoo\'));
|
||||
res\.send({ some: \'json\' });
|
||||
res\.send(\'<p>some html</p>\');
|
||||
res\.send(\'Sorry, cant find that\', 404);
|
||||
res\.send(\'text\', { \'Content\-Type\': \'text/plain\' }, 201);
|
||||
res\.send(404);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
By default the \fIContent\-Type\fR response header is set, however if explicitly assigned through \fBres\.send()\fR or previously with \fBres\.header()\fR or \fBres\.contentType()\fR it will not be set again\.
|
||||
.
|
||||
.SS "res\.redirect(url[, status])"
|
||||
Redirect to the given \fIurl\fR with a default response \fIstatus\fR of 302\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.redirect(\'/\', 301);
|
||||
res\.redirect(\'/account\');
|
||||
res\.redirect(\'http://google\.com\');
|
||||
res\.redirect(\'home\');
|
||||
res\.redirect(\'back\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Express supports \"redirect mapping\", which by default provides \fIhome\fR, and \fIback\fR\. The \fIback\fR map checks the \fIReferrer\fR and \fIReferer\fR headers, while \fIhome\fR utilizes the \"home\" setting and defaults to \"/\"\.
|
||||
.
|
||||
.SS "app\.set(name[, val])"
|
||||
Apply an application level setting \fIname\fR to \fIval\fR, or get the value of \fIname\fR when \fIval\fR is not present:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.set(\'reload views\', 200);
|
||||
app\.set(\'reload views\');
|
||||
// => 200
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.enable(name)"
|
||||
Enable the given setting \fIname\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.enable(\'some arbitrary setting\');
|
||||
app\.set(\'some arbitrary setting\');
|
||||
// => true
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.disable(name)"
|
||||
Disable the given setting \fIname\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.disable(\'some setting\');
|
||||
app\.set(\'some setting\');
|
||||
// => false
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.configure(env|function[, function])"
|
||||
Define a callback function for the given \fIenv\fR (or all environments) with callback \fIfunction\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.configure(function(){
|
||||
// executed for each env
|
||||
});
|
||||
|
||||
app\.configure(\'development\', function(){
|
||||
// executed for \'development\' only
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.redirect(name, val)"
|
||||
For use with \fBres\.redirect()\fR we can map redirects at the application level as shown below:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.redirect(\'google\', \'http://google\.com\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Now in a route we may call:
|
||||
.
|
||||
.P
|
||||
res\.redirect(\'google\');
|
||||
.
|
||||
.P
|
||||
We may also map dynamic redirects:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.redirect(\'comments\', function(req, res, params){
|
||||
return \'/post/\' + params\.id + \'/comments\';
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
So now we may do the following, and the redirect will dynamically adjust to the context of the request\. If we called this route with \fIGET /post/12\fR our redirect \fILocation\fR would be \fI/post/12/comments\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/post/:id\', function(req, res){
|
||||
res\.redirect(\'comments\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.error(function)"
|
||||
Adds an error handler \fIfunction\fR which will receive the exception as the first parameter as shown below\. Note that we may set several error handlers by making several calls to this method, however the handler should call \fInext(err)\fR if it does not wish to deal with the exception:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.error(function(err, req, res, next){
|
||||
res\.send(err\.message, 500);
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "app\.listen([port[, host]])"
|
||||
Bind the app server to the given \fIport\fR, which defaults to 3000\. When \fIhost\fR is omitted all connections will be accepted via \fIINADDR_ANY\fR\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.listen();
|
||||
app\.listen(3000);
|
||||
app\.listen(3000, \'n\.n\.n\.n\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
The \fIport\fR argument may also be a string representing the path to a unix domain socket:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.listen(\'/tmp/express\.sock\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Then try it out:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ telnet /tmp/express\.sock
|
||||
GET / HTTP/1\.1
|
||||
|
||||
HTTP/1\.1 200 OK
|
||||
Content\-Type: text/plain
|
||||
Content\-Length: 11
|
||||
|
||||
Hello World
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,787 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container"><ul id="toc">
|
||||
<li><a href="#Installation">Installation</a></li>
|
||||
<li><a href="#Creating-An-Application">Creating An Application</a></li>
|
||||
<li><a href="#Configuration">Configuration</a></li>
|
||||
<li><a href="#Settings">Settings</a></li>
|
||||
<li><a href="#Routing">Routing</a></li>
|
||||
<li><a href="#Passing-Route-Control">Passing Route Control</a></li>
|
||||
<li><a href="#Middleware">Middleware</a></li>
|
||||
<li><a href="#Error-Handling">Error Handling</a></li>
|
||||
<li><a href="#View-Rendering">View Rendering</a></li>
|
||||
<li><a href="#View-Partials">View Partials</a></li>
|
||||
<li><a href="#Template-Engines">Template Engines</a></li>
|
||||
<li><a href="#req-header-key-defaultValue-">req.header()</a></li>
|
||||
<li><a href="#req-accepts-type-">req.accepts()</a></li>
|
||||
<li><a href="#req-param-name-">req.param()</a></li>
|
||||
<li><a href="#req-flash-type-msg-">req.flash()</a></li>
|
||||
<li><a href="#req-isXMLHttpRequest">req.isXMLHttpRequest</a></li>
|
||||
<li><a href="#res-header-key-val-">res.header()</a></li>
|
||||
<li><a href="#res-contentType-type-">res.contentType()</a></li>
|
||||
<li><a href="#res-attachment-filename-">res.attachment()</a></li>
|
||||
<li><a href="#res-sendfile-path-">res.sendfile()</a></li>
|
||||
<li><a href="#res-download-file-filename-">res.download()</a></li>
|
||||
<li><a href="#res-send-body-status-headers-status-status-">res.send()</a></li>
|
||||
<li><a href="#res-redirect-url-status-">res.redirect()</a></li>
|
||||
<li><a href="#app-set-name-val-">app.set()</a></li>
|
||||
<li><a href="#app-enable-name-">app.enable()</a></li>
|
||||
<li><a href="#app-disable-name-">app.disable()</a></li>
|
||||
<li><a href="#app-configure-env-function-function-">app.configure()</a></li>
|
||||
<li><a href="#app-redirect-name-val-">app.redirect()</a></li>
|
||||
<li><a href="#app-error-function-">app.error()</a></li>
|
||||
<li><a href="#app-listen-port-host-">app.listen()</a></li>
|
||||
</ul>
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Installation">Installation</h3>
|
||||
|
||||
<p>npm:</p>
|
||||
|
||||
<pre><code>$ npm install connect
|
||||
$ npm install express
|
||||
</code></pre>
|
||||
|
||||
<p>curl (or similar):</p>
|
||||
|
||||
<pre><code>$ curl -# http://github.com/visionmedia/express/raw/master/install.sh | sh
|
||||
</code></pre>
|
||||
|
||||
<p>git clone, first update the submodules:</p>
|
||||
|
||||
<pre><code>$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Creating-An-Application">Creating An Application</h3>
|
||||
|
||||
<p>The <em>express.Server</em> now inherits from <em>http.Server</em>, however
|
||||
follows the same idiom by providing <em>express.createServer()</em> as shown below. This means
|
||||
that you can utilize Express server's transparently with other libraries.</p>
|
||||
|
||||
<pre><code>var app = require('express').createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Configuration">Configuration</h3>
|
||||
|
||||
<p>Express supports arbitrary environments, such as <em>production</em> and <em>development</em>. Developers
|
||||
can use the <em>configure()</em> method to setup needs required by the current environment. When
|
||||
<em>configure()</em> is called without an environment name it will be run in <em>every</em> environment
|
||||
prior to the environment specific callback.</p>
|
||||
|
||||
<p>In the example below we only <em>dumpExceptions</em>, and respond with exception stack traces
|
||||
in <em>development</em> mode, however for both environments we utilize <em>methodOverride</em> and <em>bodyDecoder</em>.</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
app.use('/', connect.methodOverride());
|
||||
app.use('/', connect.bodyDecoder());
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
app.use('/', connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
app.configure('production', function(){
|
||||
app.use('/', connect.errorHandler());
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>For internal and arbitrary settings Express provides the <em>set(key[, val])</em>, <em>enable(key)</em>, <em>disable(key)</em> methods:</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('views');
|
||||
// => "... views directory ..."
|
||||
|
||||
app.enable('some feature');
|
||||
// same as app.set('some feature', true);
|
||||
|
||||
app.disable('some feature');
|
||||
// same as app.set('some feature', false);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>To alter the environment we can set the <em>CONNECT_ENV</em> environment variable,
|
||||
or more specifically <em>EXPRESS_ENV</em>, for example:</p>
|
||||
|
||||
<pre><code>$ EXPRESS_ENV=production node app.js
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Settings">Settings</h3>
|
||||
|
||||
<p>Express supports the following settings out of the box:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>env</em> Application environment set internally, use <em>app.set('env')</em> to utilize</li>
|
||||
<li><em>home</em> Application base path used with <em>res.redirect()</em></li>
|
||||
<li><em>views</em> Root views directory defaulting to <strong>CWD/views</strong></li>
|
||||
<li><em>view engine</em> Default view engine name for views rendered without extensions</li>
|
||||
<li><em>reload views</em> Reloads altered views, by default watches for <em>mtime</em> changes with
|
||||
with a 5 minute interval. Example: <em>app.set('reload views', 60000);</em></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="Routing">Routing</h3>
|
||||
|
||||
<p>Express utilizes the HTTP verbs to provide a meaningful, expressive routing API.
|
||||
For example we may want to render a user's account for the path <em>/user/12</em>, this
|
||||
can be done by defining the route below. The values associated to the named placeholders,
|
||||
are passed as the <em>third</em> argument, which here we name <em>params</em>.</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(req, res, params){
|
||||
res.send('user ' + params.id);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>A route is simple a string which is compiled to a <em>RegExp</em> internally. For example
|
||||
when <em>/user/:id</em> is compiled, a simplified version of the regexp may look similar to:</p>
|
||||
|
||||
<pre><code>\/user\/([^\/]+)\/?
|
||||
</code></pre>
|
||||
|
||||
<p>Literal regular expressions may also be passed for complex uses:</p>
|
||||
|
||||
<pre><code>app.get(/^\/foo(bar)?$/, function(){});
|
||||
</code></pre>
|
||||
|
||||
<p>Below are some route examples, and the associated paths that they
|
||||
may consume:</p>
|
||||
|
||||
<pre><code> "/user/:id"
|
||||
/user/12
|
||||
|
||||
"/users/:id?"
|
||||
/users/5
|
||||
/users
|
||||
|
||||
"/files/*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/file/*.*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/user/:id/:operation?"
|
||||
/user/1
|
||||
/user/1/edit
|
||||
|
||||
"/products.:format"
|
||||
/products.json
|
||||
/products.xml
|
||||
|
||||
"/products.:format?"
|
||||
/products.json
|
||||
/products.xml
|
||||
/products
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Passing-Route-Control">Passing Route Control</h3>
|
||||
|
||||
<p>We may pass control to the next <em>matching</em> route, by calling the <em>fourth</em> parameter,
|
||||
the <em>next()</em> function. When a match cannot be made, control is passed back to Connect.</p>
|
||||
|
||||
<pre><code>app.get('/users/:id?', function(req, res, params){
|
||||
if (params.id) {
|
||||
// do something
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res, params){
|
||||
// do something else
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Middleware">Middleware</h3>
|
||||
|
||||
<p>The Express <em>Plugin</em> is no more! middleware via <a href="http://github.com/extjs/Connect">Connect</a> can be
|
||||
passed to <em>express.createServer()</em> as you would with a regular Connect server. For example:</p>
|
||||
|
||||
<pre><code>var connect = require('connect'),
|
||||
express = require('express');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.bodyDecoder()
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks:</p>
|
||||
|
||||
<pre><code>app.use('/', connect.logger({ format: ':method :uri' }));
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Error-Handling">Error Handling</h3>
|
||||
|
||||
<p>Express provides the <em>app.error()</em> method which receives exceptions thrown within a route,
|
||||
or passed to <em>next(err)</em>. Below is an example which serves different pages based on our
|
||||
ad-hoc <em>NotFound</em> exception:</p>
|
||||
|
||||
<pre><code>function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>We can call <em>app.error()</em> several times as shown below.
|
||||
Here we check for an instanceof <em>NotFound</em> and show the
|
||||
404 page, or we pass on to the next error handler.</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Here we assume all errors as 500 for the simplicity of
|
||||
this demo, however you can choose whatever you like</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Our apps could also utilize the Connect <em>errorHandler</em> middleware
|
||||
to report on exceptions. For example if we wish to output exceptions
|
||||
in "development" mode to <em>stderr</em> we can use:</p>
|
||||
|
||||
<pre><code>app.use('/', connect.errorHandler({ dumpExceptions: true }));
|
||||
</code></pre>
|
||||
|
||||
<p>Also during development we may want fancy html pages to show exceptions
|
||||
that are passed or thrown, so we can set <em>showStack</em> to true:</p>
|
||||
|
||||
<pre><code>app.use('/', connect.errorHandler({ showStack: true, dumpExceptions: true }));
|
||||
</code></pre>
|
||||
|
||||
<p>The <em>errorHandler</em> middleware also responds with <em>json</em> if <em>Accept: application/json</em>
|
||||
is present, which is useful for developing apps that rely heavily on client-side JavaScript.</p>
|
||||
|
||||
<h3 id="View-Rendering">View Rendering</h3>
|
||||
|
||||
<p>View filenames take the form <em>Express</em>.<em>ENGINE</em>, where <em>ENGINE</em> is the name
|
||||
of the module that will be required. For example the view <em>layout.ejs</em> will
|
||||
tell the view system to <em>require('ejs')</em>, the module being loaded must (currently)
|
||||
export the method <em>exports.render(str, options)</em> to comply with Express, however
|
||||
with will likely be extensible in the future.</p>
|
||||
|
||||
<p>Below is an example using <a href="http://github.com/visionmedia/haml.js">Haml.js</a> to render <em>index.html</em>,
|
||||
and since we do not use <em>layout: false</em> the rendered contents of <em>index.html</em> will be passed as
|
||||
the <em>body</em> local variable in <em>layout.haml</em>.</p>
|
||||
|
||||
<pre><code>app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="View-Partials">View Partials</h3>
|
||||
|
||||
<p>The Express view system has built-in support for partials and collections, which are
|
||||
sort of "mini" views representing a document fragment. For example rather than iterating
|
||||
in a view to display comments, we would use a partial with collection support:</p>
|
||||
|
||||
<pre><code>partial('comment.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>To make things even less verbose we can assume the extension as <em>.haml</em> when omitted,
|
||||
however if we wished we could use an ejs partial, within a haml view for example.</p>
|
||||
|
||||
<pre><code>partial('comment', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:</p>
|
||||
|
||||
<pre><code>partial('comments', comments);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Template-Engines">Template Engines</h3>
|
||||
|
||||
<p>Below are a few template engines commonly used with Express:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://github.com/visionmedia/jade">Jade</a> haml.js successor</li>
|
||||
<li><a href="http://github.com/visionmedia/haml.js">Haml</a> indented templates</li>
|
||||
<li><a href="http://github.com/visionmedia/ejs">EJS</a> Embedded JavaScript</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="req-header-key-defaultValue-">req.header(key[, defaultValue])</h3>
|
||||
|
||||
<p>Get the case-insensitive request header <em>key</em>, with optional <em>defaultValue</em>:</p>
|
||||
|
||||
<pre><code>req.header('Host');
|
||||
req.header('host');
|
||||
req.header('Accept', '*/*');
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-accepts-type-">req.accepts(type)</h3>
|
||||
|
||||
<p>Check if the <em>Accept</em> header is present, and includes the given <em>type</em>.</p>
|
||||
|
||||
<p>When the <em>Accept</em> header is not present <em>true</em> is returned. Otherwise
|
||||
the given <em>type</em> is matched by an exact match, and then subtypes. You
|
||||
may pass the subtype such as "html" which is then converted internally
|
||||
to "text/html" using the mime lookup table.</p>
|
||||
|
||||
<pre><code>// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/html');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-param-name-">req.param(name)</h3>
|
||||
|
||||
<p>Return the value of param <em>name</em> when present.</p>
|
||||
|
||||
<ul>
|
||||
<li>Checks route placeholders, ex: /user/:id</li>
|
||||
<li>Checks query string params, ex: ?id=12</li>
|
||||
<li>Checks urlencoded body params, ex: id=12</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>To utilize urlencoded request bodies, <em>req.body</em>
|
||||
should be an object. This can be done by using
|
||||
the <em>connect.bodyDecoder</em> middleware.</p>
|
||||
|
||||
<h3 id="req-flash-type-msg-">req.flash(type[, msg])</h3>
|
||||
|
||||
<p>Queue flash <em>msg</em> of the given <em>type</em>.</p>
|
||||
|
||||
<pre><code>req.flash('info', 'email sent');
|
||||
req.flash('error', 'email delivery failed');
|
||||
req.flash('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.flash('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.flash('info');
|
||||
// => []
|
||||
|
||||
req.flash();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-isXMLHttpRequest">req.isXMLHttpRequest</h3>
|
||||
|
||||
<p>Also aliased as <em>req.xhr</em>, this getter checks the <em>X-Requested-With</em> header
|
||||
to see if it was issued by an <em>XMLHttpRequest</em>:</p>
|
||||
|
||||
<pre><code>req.xhr
|
||||
req.isXMLHttpRequest
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-header-key-val-">res.header(key[, val])</h3>
|
||||
|
||||
<p>Get or set the response header <em>key</em>.</p>
|
||||
|
||||
<pre><code>res.header('Content-Length');
|
||||
// => undefined
|
||||
|
||||
res.header('Content-Length', 123);
|
||||
// => 123
|
||||
|
||||
res.header('Content-Length');
|
||||
// => 123
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-contentType-type-">res.contentType(type)</h3>
|
||||
|
||||
<p>Sets the <em>Content-Type</em> response header to the given <em>type</em>.</p>
|
||||
|
||||
<pre><code> var filename = 'path/to/image.png';
|
||||
res.contentType(filename);
|
||||
// res.headers['Content-Type'] is now "image/png"
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-attachment-filename-">res.attachment([filename])</h3>
|
||||
|
||||
<p>Sets the <em>Content-Disposition</em> response header to "attachment", with optional <em>filename</em>.</p>
|
||||
|
||||
<pre><code> res.attachment('path/to/my/image.png');
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-sendfile-path-">res.sendfile(path)</h3>
|
||||
|
||||
<p>Used by <code>res.download()</code> to transfer an arbitrary file.</p>
|
||||
|
||||
<pre><code>res.sendfile('path/to/my.file');
|
||||
</code></pre>
|
||||
|
||||
<p><strong>NOTE</strong>: this is <em>not</em> a replacement for Connect's <em>staticProvider</em> middleware,
|
||||
nor does it perform any security checks, use with caution when using in a dynamic manor.</p>
|
||||
|
||||
<h3 id="res-download-file-filename-">res.download(file[, filename])</h3>
|
||||
|
||||
<p>Transfer the given <em>file</em> as an attachment with optional alternative <em>filename</em>.</p>
|
||||
|
||||
<pre><code>res.download('path/to/image.png');
|
||||
res.download('path/to/image.png', 'foo.png');
|
||||
</code></pre>
|
||||
|
||||
<p>This is equivalent to:</p>
|
||||
|
||||
<pre><code>res.attachment(file);
|
||||
res.sendfile(file);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-send-body-status-headers-status-status-">res.send(body|status[, headers|status[, status]])</h3>
|
||||
|
||||
<p>The <code>res.send()</code> method is a high level response utility allowing you to pass
|
||||
objects to respond with json, strings for html, arbitrary _Buffer_s or numbers for status
|
||||
code based responses. The following are all valid uses:</p>
|
||||
|
||||
<pre><code> res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
</code></pre>
|
||||
|
||||
<p>By default the <em>Content-Type</em> response header is set, however if explicitly
|
||||
assigned through <code>res.send()</code> or previously with <code>res.header()</code> or <code>res.contentType()</code>
|
||||
it will not be set again.</p>
|
||||
|
||||
<h3 id="res-redirect-url-status-">res.redirect(url[, status])</h3>
|
||||
|
||||
<p>Redirect to the given <em>url</em> with a default response <em>status</em> of 302.</p>
|
||||
|
||||
<pre><code>res.redirect('/', 301);
|
||||
res.redirect('/account');
|
||||
res.redirect('http://google.com');
|
||||
res.redirect('home');
|
||||
res.redirect('back');
|
||||
</code></pre>
|
||||
|
||||
<p>Express supports "redirect mapping", which by default provides <em>home</em>, and <em>back</em>.
|
||||
The <em>back</em> map checks the <em>Referrer</em> and <em>Referer</em> headers, while <em>home</em> utilizes
|
||||
the "home" setting and defaults to "/".</p>
|
||||
|
||||
<h3 id="app-set-name-val-">app.set(name[, val])</h3>
|
||||
|
||||
<p>Apply an application level setting <em>name</em> to <em>val</em>, or
|
||||
get the value of <em>name</em> when <em>val</em> is not present:</p>
|
||||
|
||||
<pre><code>app.set('reload views', 200);
|
||||
app.set('reload views');
|
||||
// => 200
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-enable-name-">app.enable(name)</h3>
|
||||
|
||||
<p>Enable the given setting <em>name</em>:</p>
|
||||
|
||||
<pre><code>app.enable('some arbitrary setting');
|
||||
app.set('some arbitrary setting');
|
||||
// => true
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-disable-name-">app.disable(name)</h3>
|
||||
|
||||
<p>Disable the given setting <em>name</em>:</p>
|
||||
|
||||
<pre><code>app.disable('some setting');
|
||||
app.set('some setting');
|
||||
// => false
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-configure-env-function-function-">app.configure(env|function[, function])</h3>
|
||||
|
||||
<p>Define a callback function for the given <em>env</em> (or all environments) with callback <em>function</em>:</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
// executed for each env
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
// executed for 'development' only
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-redirect-name-val-">app.redirect(name, val)</h3>
|
||||
|
||||
<p>For use with <code>res.redirect()</code> we can map redirects at the application level as shown below:</p>
|
||||
|
||||
<pre><code>app.redirect('google', 'http://google.com');
|
||||
</code></pre>
|
||||
|
||||
<p>Now in a route we may call:</p>
|
||||
|
||||
<p> res.redirect('google');</p>
|
||||
|
||||
<p>We may also map dynamic redirects:</p>
|
||||
|
||||
<pre><code>app.redirect('comments', function(req, res, params){
|
||||
return '/post/' + params.id + '/comments';
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>So now we may do the following, and the redirect will dynamically adjust to
|
||||
the context of the request. If we called this route with <em>GET /post/12</em> our
|
||||
redirect <em>Location</em> would be <em>/post/12/comments</em>.</p>
|
||||
|
||||
<pre><code>app.get('/post/:id', function(req, res){
|
||||
res.redirect('comments');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-error-function-">app.error(function)</h3>
|
||||
|
||||
<p>Adds an error handler <em>function</em> which will receive the exception as the first parameter as shown below.
|
||||
Note that we may set several error handlers by making several calls to this method, however the handler
|
||||
should call <em>next(err)</em> if it does not wish to deal with the exception:</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-listen-port-host-">app.listen([port[, host]])</h3>
|
||||
|
||||
<p>Bind the app server to the given <em>port</em>, which defaults to 3000. When <em>host</em> is omitted all
|
||||
connections will be accepted via <em>INADDR_ANY</em>.</p>
|
||||
|
||||
<pre><code>app.listen();
|
||||
app.listen(3000);
|
||||
app.listen(3000, 'n.n.n.n');
|
||||
</code></pre>
|
||||
|
||||
<p>The <em>port</em> argument may also be a string representing the path to a unix domain socket:</p>
|
||||
|
||||
<pre><code>app.listen('/tmp/express.sock');
|
||||
</code></pre>
|
||||
|
||||
<p>Then try it out:</p>
|
||||
|
||||
<pre><code>$ telnet /tmp/express.sock
|
||||
GET / HTTP/1.1
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
Content-Length: 11
|
||||
|
||||
Hello World
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+516
@@ -0,0 +1,516 @@
|
||||
|
||||
### Installation
|
||||
|
||||
npm:
|
||||
|
||||
$ npm install connect
|
||||
$ npm install express
|
||||
|
||||
curl (or similar):
|
||||
|
||||
$ curl -# http://github.com/visionmedia/express/raw/master/install.sh | sh
|
||||
|
||||
git clone, first update the submodules:
|
||||
|
||||
$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
|
||||
### Creating An Application
|
||||
|
||||
The _express.Server_ now inherits from _http.Server_, however
|
||||
follows the same idiom by providing _express.createServer()_ as shown below. This means
|
||||
that you can utilize Express server's transparently with other libraries.
|
||||
|
||||
var app = require('express').createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
### Configuration
|
||||
|
||||
Express supports arbitrary environments, such as _production_ and _development_. Developers
|
||||
can use the _configure()_ method to setup needs required by the current environment. When
|
||||
_configure()_ is called without an environment name it will be run in _every_ environment
|
||||
prior to the environment specific callback.
|
||||
|
||||
In the example below we only _dumpExceptions_, and respond with exception stack traces
|
||||
in _development_ mode, however for both environments we utilize _methodOverride_ and _bodyDecoder_.
|
||||
|
||||
app.configure(function(){
|
||||
app.use('/', connect.methodOverride());
|
||||
app.use('/', connect.bodyDecoder());
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
app.use('/', connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
app.configure('production', function(){
|
||||
app.use('/', connect.errorHandler());
|
||||
});
|
||||
|
||||
For internal and arbitrary settings Express provides the _set(key[, val])_, _enable(key)_, _disable(key)_ methods:
|
||||
|
||||
app.configure(function(){
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('views');
|
||||
// => "... views directory ..."
|
||||
|
||||
app.enable('some feature');
|
||||
// same as app.set('some feature', true);
|
||||
|
||||
app.disable('some feature');
|
||||
// same as app.set('some feature', false);
|
||||
});
|
||||
|
||||
To alter the environment we can set the _CONNECT_ENV_ environment variable,
|
||||
or more specifically _EXPRESS_ENV_, for example:
|
||||
|
||||
$ EXPRESS_ENV=production node app.js
|
||||
|
||||
### Settings
|
||||
|
||||
Express supports the following settings out of the box:
|
||||
|
||||
* _env_ Application environment set internally, use _app.set('env')_ to utilize
|
||||
* _home_ Application base path used with _res.redirect()_
|
||||
* _views_ Root views directory defaulting to **CWD/views**
|
||||
* _view engine_ Default view engine name for views rendered without extensions
|
||||
* _reload views_ Reloads altered views, by default watches for _mtime_ changes with
|
||||
with a 5 minute interval. Example: _app.set('reload views', 60000);_
|
||||
|
||||
### Routing
|
||||
|
||||
Express utilizes the HTTP verbs to provide a meaningful, expressive routing API.
|
||||
For example we may want to render a user's account for the path _/user/12_, this
|
||||
can be done by defining the route below. The values associated to the named placeholders,
|
||||
are passed as the _third_ argument, which here we name _params_.
|
||||
|
||||
app.get('/user/:id', function(req, res, params){
|
||||
res.send('user ' + params.id);
|
||||
});
|
||||
|
||||
A route is simple a string which is compiled to a _RegExp_ internally. For example
|
||||
when _/user/:id_ is compiled, a simplified version of the regexp may look similar to:
|
||||
|
||||
\/user\/([^\/]+)\/?
|
||||
|
||||
Literal regular expressions may also be passed for complex uses:
|
||||
|
||||
app.get(/^\/foo(bar)?$/, function(){});
|
||||
|
||||
Below are some route examples, and the associated paths that they
|
||||
may consume:
|
||||
|
||||
"/user/:id"
|
||||
/user/12
|
||||
|
||||
"/users/:id?"
|
||||
/users/5
|
||||
/users
|
||||
|
||||
"/files/*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/file/*.*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/user/:id/:operation?"
|
||||
/user/1
|
||||
/user/1/edit
|
||||
|
||||
"/products.:format"
|
||||
/products.json
|
||||
/products.xml
|
||||
|
||||
"/products.:format?"
|
||||
/products.json
|
||||
/products.xml
|
||||
/products
|
||||
|
||||
### Passing Route Control
|
||||
|
||||
We may pass control to the next _matching_ route, by calling the _fourth_ parameter,
|
||||
the _next()_ function. When a match cannot be made, control is passed back to Connect.
|
||||
|
||||
app.get('/users/:id?', function(req, res, params){
|
||||
if (params.id) {
|
||||
// do something
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res, params){
|
||||
// do something else
|
||||
});
|
||||
|
||||
### Middleware
|
||||
|
||||
The Express _Plugin_ is no more! middleware via [Connect](http://github.com/extjs/Connect) can be
|
||||
passed to _express.createServer()_ as you would with a regular Connect server. For example:
|
||||
|
||||
var connect = require('connect'),
|
||||
express = require('express');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.bodyDecoder()
|
||||
);
|
||||
|
||||
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks:
|
||||
|
||||
app.use('/', connect.logger({ format: ':method :uri' }));
|
||||
|
||||
### Error Handling
|
||||
|
||||
Express provides the _app.error()_ method which receives exceptions thrown within a route,
|
||||
or passed to _next(err)_. Below is an example which serves different pages based on our
|
||||
ad-hoc _NotFound_ exception:
|
||||
|
||||
function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
|
||||
We can call _app.error()_ several times as shown below.
|
||||
Here we check for an instanceof _NotFound_ and show the
|
||||
404 page, or we pass on to the next error handler.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
Here we assume all errors as 500 for the simplicity of
|
||||
this demo, however you can choose whatever you like
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Our apps could also utilize the Connect _errorHandler_ middleware
|
||||
to report on exceptions. For example if we wish to output exceptions
|
||||
in "development" mode to _stderr_ we can use:
|
||||
|
||||
app.use('/', connect.errorHandler({ dumpExceptions: true }));
|
||||
|
||||
Also during development we may want fancy html pages to show exceptions
|
||||
that are passed or thrown, so we can set _showStack_ to true:
|
||||
|
||||
app.use('/', connect.errorHandler({ showStack: true, dumpExceptions: true }));
|
||||
|
||||
The _errorHandler_ middleware also responds with _json_ if _Accept: application/json_
|
||||
is present, which is useful for developing apps that rely heavily on client-side JavaScript.
|
||||
|
||||
### View Rendering
|
||||
|
||||
View filenames take the form _NAME_._ENGINE_, where _ENGINE_ is the name
|
||||
of the module that will be required. For example the view _layout.ejs_ will
|
||||
tell the view system to _require('ejs')_, the module being loaded must (currently)
|
||||
export the method _exports.render(str, options)_ to comply with Express, however
|
||||
with will likely be extensible in the future.
|
||||
|
||||
Below is an example using [Haml.js](http://github.com/visionmedia/haml.js) to render _index.html_,
|
||||
and since we do not use _layout: false_ the rendered contents of _index.html_ will be passed as
|
||||
the _body_ local variable in _layout.haml_.
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
### View Partials
|
||||
|
||||
The Express view system has built-in support for partials and collections, which are
|
||||
sort of "mini" views representing a document fragment. For example rather than iterating
|
||||
in a view to display comments, we would use a partial with collection support:
|
||||
|
||||
partial('comment.haml', { collection: comments });
|
||||
|
||||
To make things even less verbose we can assume the extension as _.haml_ when omitted,
|
||||
however if we wished we could use an ejs partial, within a haml view for example.
|
||||
|
||||
partial('comment', { collection: comments });
|
||||
|
||||
And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:
|
||||
|
||||
partial('comments', comments);
|
||||
|
||||
### Template Engines
|
||||
|
||||
Below are a few template engines commonly used with Express:
|
||||
|
||||
* [Jade](http://github.com/visionmedia/jade) haml.js successor
|
||||
* [Haml](http://github.com/visionmedia/haml.js) indented templates
|
||||
* [EJS](http://github.com/visionmedia/ejs) Embedded JavaScript
|
||||
|
||||
### req.header(key[, defaultValue])
|
||||
|
||||
Get the case-insensitive request header _key_, with optional _defaultValue_:
|
||||
|
||||
req.header('Host');
|
||||
req.header('host');
|
||||
req.header('Accept', '*/*');
|
||||
|
||||
### req.accepts(type)
|
||||
|
||||
Check if the _Accept_ header is present, and includes the given _type_.
|
||||
|
||||
When the _Accept_ header is not present _true_ is returned. Otherwise
|
||||
the given _type_ is matched by an exact match, and then subtypes. You
|
||||
may pass the subtype such as "html" which is then converted internally
|
||||
to "text/html" using the mime lookup table.
|
||||
|
||||
// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/html');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
|
||||
### req.param(name)
|
||||
|
||||
Return the value of param _name_ when present.
|
||||
|
||||
- Checks route placeholders, ex: /user/:id
|
||||
- Checks query string params, ex: ?id=12
|
||||
- Checks urlencoded body params, ex: id=12
|
||||
|
||||
To utilize urlencoded request bodies, _req.body_
|
||||
should be an object. This can be done by using
|
||||
the _connect.bodyDecoder_ middleware.
|
||||
|
||||
### req.flash(type[, msg])
|
||||
|
||||
Queue flash _msg_ of the given _type_.
|
||||
|
||||
req.flash('info', 'email sent');
|
||||
req.flash('error', 'email delivery failed');
|
||||
req.flash('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.flash('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.flash('info');
|
||||
// => []
|
||||
|
||||
req.flash();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
|
||||
### req.isXMLHttpRequest
|
||||
|
||||
Also aliased as _req.xhr_, this getter checks the _X-Requested-With_ header
|
||||
to see if it was issued by an _XMLHttpRequest_:
|
||||
|
||||
req.xhr
|
||||
req.isXMLHttpRequest
|
||||
|
||||
### res.header(key[, val])
|
||||
|
||||
Get or set the response header _key_.
|
||||
|
||||
res.header('Content-Length');
|
||||
// => undefined
|
||||
|
||||
res.header('Content-Length', 123);
|
||||
// => 123
|
||||
|
||||
res.header('Content-Length');
|
||||
// => 123
|
||||
|
||||
### res.contentType(type)
|
||||
|
||||
Sets the _Content-Type_ response header to the given _type_.
|
||||
|
||||
var filename = 'path/to/image.png';
|
||||
res.contentType(filename);
|
||||
// res.headers['Content-Type'] is now "image/png"
|
||||
|
||||
### res.attachment([filename])
|
||||
|
||||
Sets the _Content-Disposition_ response header to "attachment", with optional _filename_.
|
||||
|
||||
res.attachment('path/to/my/image.png');
|
||||
|
||||
### res.sendfile(path)
|
||||
|
||||
Used by `res.download()` to transfer an arbitrary file.
|
||||
|
||||
res.sendfile('path/to/my.file');
|
||||
|
||||
**NOTE**: this is _not_ a replacement for Connect's _staticProvider_ middleware,
|
||||
nor does it perform any security checks, use with caution when using in a dynamic manor.
|
||||
|
||||
### res.download(file[, filename])
|
||||
|
||||
Transfer the given _file_ as an attachment with optional alternative _filename_.
|
||||
|
||||
res.download('path/to/image.png');
|
||||
res.download('path/to/image.png', 'foo.png');
|
||||
|
||||
This is equivalent to:
|
||||
|
||||
res.attachment(file);
|
||||
res.sendfile(file);
|
||||
|
||||
### res.send(body|status[, headers|status[, status]])
|
||||
|
||||
The `res.send()` method is a high level response utility allowing you to pass
|
||||
objects to respond with json, strings for html, arbitrary _Buffer_s or numbers for status
|
||||
code based responses. The following are all valid uses:
|
||||
|
||||
res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
|
||||
By default the _Content-Type_ response header is set, however if explicitly
|
||||
assigned through `res.send()` or previously with `res.header()` or `res.contentType()`
|
||||
it will not be set again.
|
||||
|
||||
### res.redirect(url[, status])
|
||||
|
||||
Redirect to the given _url_ with a default response _status_ of 302.
|
||||
|
||||
res.redirect('/', 301);
|
||||
res.redirect('/account');
|
||||
res.redirect('http://google.com');
|
||||
res.redirect('home');
|
||||
res.redirect('back');
|
||||
|
||||
Express supports "redirect mapping", which by default provides _home_, and _back_.
|
||||
The _back_ map checks the _Referrer_ and _Referer_ headers, while _home_ utilizes
|
||||
the "home" setting and defaults to "/".
|
||||
|
||||
### app.set(name[, val])
|
||||
|
||||
Apply an application level setting _name_ to _val_, or
|
||||
get the value of _name_ when _val_ is not present:
|
||||
|
||||
app.set('reload views', 200);
|
||||
app.set('reload views');
|
||||
// => 200
|
||||
|
||||
### app.enable(name)
|
||||
|
||||
Enable the given setting _name_:
|
||||
|
||||
app.enable('some arbitrary setting');
|
||||
app.set('some arbitrary setting');
|
||||
// => true
|
||||
|
||||
### app.disable(name)
|
||||
|
||||
Disable the given setting _name_:
|
||||
|
||||
app.disable('some setting');
|
||||
app.set('some setting');
|
||||
// => false
|
||||
|
||||
### app.configure(env|function[, function])
|
||||
|
||||
Define a callback function for the given _env_ (or all environments) with callback _function_:
|
||||
|
||||
app.configure(function(){
|
||||
// executed for each env
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
// executed for 'development' only
|
||||
});
|
||||
|
||||
### app.redirect(name, val)
|
||||
|
||||
For use with `res.redirect()` we can map redirects at the application level as shown below:
|
||||
|
||||
app.redirect('google', 'http://google.com');
|
||||
|
||||
Now in a route we may call:
|
||||
|
||||
res.redirect('google');
|
||||
|
||||
We may also map dynamic redirects:
|
||||
|
||||
app.redirect('comments', function(req, res, params){
|
||||
return '/post/' + params.id + '/comments';
|
||||
});
|
||||
|
||||
So now we may do the following, and the redirect will dynamically adjust to
|
||||
the context of the request. If we called this route with _GET /post/12_ our
|
||||
redirect _Location_ would be _/post/12/comments_.
|
||||
|
||||
app.get('/post/:id', function(req, res){
|
||||
res.redirect('comments');
|
||||
});
|
||||
|
||||
### app.error(function)
|
||||
|
||||
Adds an error handler _function_ which will receive the exception as the first parameter as shown below.
|
||||
Note that we may set several error handlers by making several calls to this method, however the handler
|
||||
should call _next(err)_ if it does not wish to deal with the exception:
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
|
||||
### app.listen([port[, host]])
|
||||
|
||||
Bind the app server to the given _port_, which defaults to 3000. When _host_ is omitted all
|
||||
connections will be accepted via _INADDR_ANY_.
|
||||
|
||||
app.listen();
|
||||
app.listen(3000);
|
||||
app.listen(3000, 'n.n.n.n');
|
||||
|
||||
The _port_ argument may also be a string representing the path to a unix domain socket:
|
||||
|
||||
app.listen('/tmp/express.sock');
|
||||
|
||||
Then try it out:
|
||||
|
||||
$ telnet /tmp/express.sock
|
||||
GET / HTTP/1.1
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
Content-Length: 11
|
||||
|
||||
Hello World
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 108 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 7.0 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 7.2 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 143 B |
@@ -0,0 +1,85 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "INDEX" "" "July 2010" "" ""
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var app = express\.createServer();
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.send(\'Hello World\');
|
||||
});
|
||||
|
||||
app\.listen(3000);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "Features"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Robust routing
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Redirection helpers
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Focus on high performance
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View rendering and partials support
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Environment based configuration
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Session based flash notifications
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Built on Connect \fIhttp://extjs\.github\.com/Connect\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Executable \fIexecutable\.html\fR for generating applications quickly
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "Contributors"
|
||||
The following are the major contributors of Express (in no specific order)\.
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
TJ Holowaychuk (visionmedia \fIhttp://github\.com/visionmedia\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Ciaran Jessup (ciaranj \fIhttp://github\.com/ciaranj\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Aaron Heckmann (aheckmann \fIhttp://github\.com/aheckmann\fR)
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "More Information"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Google Group \fIhttp://groups\.google\.com/group/express\-js\fR for discussion
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Follow tjholowaychuk \fIhttp://twitter\.com/tjholowaychuk\fR on twitter for updates
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Annotated source documentation \fIapi\.html\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the source \fIhttp://github\.com/visionmedia/express\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the Connect \fIhttp://github\.com/extjs/Connect\fR repo for middleware usage
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the Connect Wiki \fIhttp://wiki\.github\.com/extjs/Connect/\fR for contrib middleware
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<pre><code>var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h2 id="Features">Features</h2>
|
||||
|
||||
<ul>
|
||||
<li>Robust routing</li>
|
||||
<li>Redirection helpers</li>
|
||||
<li>Focus on high performance</li>
|
||||
<li>View rendering and partials support</li>
|
||||
<li>Environment based configuration</li>
|
||||
<li>Session based flash notifications</li>
|
||||
<li>Built on <a href="http://extjs.github.com/Connect">Connect</a></li>
|
||||
<li><a href="executable.html">Executable</a> for generating applications quickly</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="Contributors">Contributors</h2>
|
||||
|
||||
<p>The following are the major contributors of Express (in no specific order).</p>
|
||||
|
||||
<ul>
|
||||
<li>TJ Holowaychuk (<a href="http://github.com/visionmedia">visionmedia</a>)</li>
|
||||
<li>Ciaran Jessup (<a href="http://github.com/ciaranj">ciaranj</a>)</li>
|
||||
<li>Aaron Heckmann (<a href="http://github.com/aheckmann">aheckmann</a>)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="More-Information">More Information</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>Follow <a href="http://twitter.com/tjholowaychuk">tjholowaychuk</a> on twitter for updates</li>
|
||||
<li>Annotated source <a href="api.html">documentation</a></li>
|
||||
<li>View the <a href="http://github.com/visionmedia/express">source</a></li>
|
||||
<li>View the <a href="http://github.com/extjs/Connect">Connect</a> repo for middleware usage</li>
|
||||
<li>View the <a href="http://wiki.github.com/extjs/Connect/">Connect Wiki</a> for contrib middleware</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://extjs.github.com/Connect)
|
||||
* [Executable](executable.html) for generating applications quickly
|
||||
|
||||
## Contributors
|
||||
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
|
||||
## More Information
|
||||
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Annotated source [documentation](api.html)
|
||||
* View the [source](http://github.com/visionmedia/express)
|
||||
* View the [Connect](http://github.com/extjs/Connect) repo for middleware usage
|
||||
* View the [Connect Wiki](http://wiki.github.com/extjs/Connect/) for contrib middleware
|
||||
@@ -0,0 +1,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,179 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,347 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "MIGRATE" "" "July 2010" "" ""
|
||||
.
|
||||
.SS "Built On Connect"
|
||||
Express 1\.x is written to run on\-top of the Connect \fIhttp://extjs\.github\.com/Connect\fR middlware framework, thus the \fIPlugin\fR has been replaced by Connect\'s middleware\. By abstracting our middleware to Connect we allow additional community frameworks to develop robust, high\-level frameworks using the same technologies as Express\.
|
||||
.
|
||||
.SS "Creating Applications"
|
||||
Previously due to legacy code implemented in the early days of node, Express unfortunately had some globals\. The DSL would previously be accessed as shown below:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
require(\'express\');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get(\'/\', function(){
|
||||
return \'hello world\';
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Now we utilize the CommonJS module system appropriately, and introduce \fIexpress\.createServer()\fR which accepts the same arguments as \fIhttp\.createServer()\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var express = require(\'express\'),
|
||||
app = express\.createServer();
|
||||
|
||||
app\.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.send(\'hello world\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Express 1\.x does \fInot\fR currently allow returning of a string\.
|
||||
.
|
||||
.SS "Plugins vs Middleware"
|
||||
Previously Express was bundled with plugins, which were essentially what are now Connect middleware\. Previously plugins would be utilized in a manor similar to below:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Which we can now \fIuse()\fR within our app, or pass to the \fIexpress\.createServer()\fR method:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var connect = require(\'connect\');
|
||||
|
||||
var app = express\.createServer(
|
||||
connect\.logger(),
|
||||
connect\.methodOverride(),
|
||||
connect\.cookie()
|
||||
);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
or:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var connect = require(\'connect\');
|
||||
var app = express\.createServer();
|
||||
|
||||
app\.use(\'/\', connect\.logger());
|
||||
app\.use(\'/\', connect\.methodOverride());
|
||||
app\.use(\'/\', connect\.cookieDecoder());
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
For documentation on creating Connect middleware visit Middleware Authoring \fIhttp://extjs\.github\.com/Connect/#Middleware\-Authoring\fR\.
|
||||
.
|
||||
.SS "Running Applications"
|
||||
Previously a global function \fIrun()\fR, was available:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
run();
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
The new \fIexpress\.Server\fR has the same API as \fIhttp\.Server\fR, so we can do things like:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.listen();
|
||||
app\.listen(3000);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Route Parameters"
|
||||
Previously we could use \fIthis\.param()\fR to attempt fetching a route, query string, or request body parameter:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/user/:id\', function(){
|
||||
this\.param(\'id\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Polymorphic parameter access can be done using \fBreq\.param()\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id\', function(){
|
||||
req\.param(\'id\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Route parameters are also passed as the third argument:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id\', function(req, res, params){
|
||||
params\.id;
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Passing Route Control"
|
||||
Old express had a weak notion of route passing, which did not support async, and was never properly implemented for practical use:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/\', function(){
|
||||
this\.pass(\'/foobar\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Now Express has access to Connect\'s \fInext()\fR function, which is passed as the fourth and final argument\. Calling \fInext()\fR will pass control to the next \fImatching route\fR, or continue down the stack of Connect middleware\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id?\', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app\.get(\'/user\', function(){
|
||||
// \.\.\. respond
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "View Rendering"
|
||||
View filenames no longer take the form \fINAME\fR\.\fITYPE\fR\.\fIENGINE\fR, the \fIContent\-Type\fR can be set via \fIres\.contentType()\fR or \fIres\.header()\fR\. For example what was previously \fIlayout\.html\.haml\fR, should now be \fIlayout\.haml\fR\.
|
||||
.
|
||||
.P
|
||||
Previously a view render looked something like this:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/\', function(){
|
||||
this\.render(\'index\.html\.haml\', {
|
||||
locals: { title: \'My Site\' }
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
We now have \fIres\.render()\fR, however the options passed to haml \fIhttp://github\.com/visionmedia/haml\.js\fR, jade \fIhttp://github\.com/visionmedia/jade\fR, and others remain the same\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.render(\'index\.haml\', {
|
||||
locals: { title: \'My Site\' }
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Previously rendering of a collection via \fIpartial()\fR would look something like this:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
this\.partial(\'comment\.html\.haml\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Although this worked just fine, it was generally to verbose, the similar but new API looks like this, as \fIpartial()\fR is \fIalways\fR passed as a local variable:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\.haml\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To make things even less verbose we can assume the extension when omitted:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
And once again even further, when rendering a collection we can simply pass an array, if no other options are desired:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comments\', comments);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Redirecting"
|
||||
Previously you would
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
this\.redirect(\'/somewhere\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
However you would now:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.redirect(\'/somewhere\');
|
||||
res\.redirect(\'/somewhere\', 301);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "HTTP Client"
|
||||
Previously Express provided a high level http client, this library is no more as it does not belong in Express, however it may be resurrected as a separate module\.
|
||||
.
|
||||
.SS "Core Extensions"
|
||||
Express is no longer dependent on the JavaScript Extensions \fIhttp://github\.com/visionmedia/ext\.js\fR library, so those of you using the methods provided by it such as \fBObject\.merge(a, b)\fR will need to roll your own, or install the module via:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ npm install ext
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 1px 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Built-On-Connect">Built On Connect</h3>
|
||||
|
||||
<p>Express 1.x is written to run on-top of the <a href="http://extjs.github.com/Connect">Connect</a> middlware
|
||||
framework, thus the <em>Plugin</em> has been replaced by Connect's middleware. By abstracting our middleware
|
||||
to Connect we allow additional community frameworks to develop robust, high-level frameworks using
|
||||
the same technologies as Express.</p>
|
||||
|
||||
<h3 id="Creating-Applications">Creating Applications</h3>
|
||||
|
||||
<p>Previously due to legacy code implemented in the early days of node,
|
||||
Express unfortunately had some globals. The DSL would previously be
|
||||
accessed as shown below:</p>
|
||||
|
||||
<pre><code>require('express');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get('/', function(){
|
||||
return 'hello world';
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Now we utilize the CommonJS module system appropriately, and
|
||||
introduce <em>express.createServer()</em> which accepts the same arguments
|
||||
as <em>http.createServer()</em>:</p>
|
||||
|
||||
<pre><code>var express = require('express'),
|
||||
app = express.createServer();
|
||||
|
||||
app.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Express 1.x does <em>not</em> currently allow returning of a string.</p>
|
||||
|
||||
<h3 id="Plugins-vs-Middleware">Plugins vs Middleware</h3>
|
||||
|
||||
<p>Previously Express was bundled with plugins, which were essentially what
|
||||
are now Connect middleware. Previously plugins would be utilized in a manor
|
||||
similar to below:</p>
|
||||
|
||||
<pre><code>use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
</code></pre>
|
||||
|
||||
<p>Which we can now <em>use()</em> within our app, or pass to the <em>express.createServer()</em> method:</p>
|
||||
|
||||
<pre><code>var connect = require('connect');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.methodOverride(),
|
||||
connect.cookie()
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>or:</p>
|
||||
|
||||
<pre><code>var connect = require('connect');
|
||||
var app = express.createServer();
|
||||
|
||||
app.use('/', connect.logger());
|
||||
app.use('/', connect.methodOverride());
|
||||
app.use('/', connect.cookieDecoder());
|
||||
</code></pre>
|
||||
|
||||
<p>For documentation on creating Connect middleware visit <a href="http://extjs.github.com/Connect/#Middleware-Authoring">Middleware Authoring</a>.</p>
|
||||
|
||||
<h3 id="Running-Applications">Running Applications</h3>
|
||||
|
||||
<p>Previously a global function <em>run()</em>, was available:</p>
|
||||
|
||||
<pre><code>run();
|
||||
</code></pre>
|
||||
|
||||
<p>The new <em>express.Server</em> has the same API as <em>http.Server</em>,
|
||||
so we can do things like:</p>
|
||||
|
||||
<pre><code>app.listen();
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Route-Parameters">Route Parameters</h3>
|
||||
|
||||
<p>Previously we could use <em>this.param()</em> to attempt
|
||||
fetching a route, query string, or request body parameter:</p>
|
||||
|
||||
<pre><code>get('/user/:id', function(){
|
||||
this.param('id');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Polymorphic parameter access can be done using <code>req.param()</code>:</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(){
|
||||
req.param('id');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Route parameters are also passed as the third argument:</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(req, res, params){
|
||||
params.id;
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Passing-Route-Control">Passing Route Control</h3>
|
||||
|
||||
<p>Old express had a weak notion of route passing,
|
||||
which did not support async, and was never properly
|
||||
implemented for practical use:</p>
|
||||
|
||||
<pre><code>get('/', function(){
|
||||
this.pass('/foobar');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Now Express has access to Connect's <em>next()</em> function,
|
||||
which is passed as the fourth and final argument. Calling <em>next()</em> will
|
||||
pass control to the next <em>matching route</em>, or continue down the stack
|
||||
of Connect middleware.</p>
|
||||
|
||||
<pre><code>app.get('/user/:id?', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user', function(){
|
||||
// ... respond
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="View-Rendering">View Rendering</h3>
|
||||
|
||||
<p>View filenames no longer take the form <em>Express</em>.<em>TYPE</em>.<em>ENGINE</em>,
|
||||
the <em>Content-Type</em> can be set via <em>res.contentType()</em> or
|
||||
<em>res.header()</em>. For example what was previously <em>layout.html.haml</em>,
|
||||
should now be <em>layout.haml</em>.</p>
|
||||
|
||||
<p>Previously a view render looked something like this:</p>
|
||||
|
||||
<pre><code>get('/', function(){
|
||||
this.render('index.html.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>We now have <em>res.render()</em>, however the options passed to <a href="http://github.com/visionmedia/haml.js">haml</a>, <a href="http://github.com/visionmedia/jade">jade</a>, and others
|
||||
remain the same.</p>
|
||||
|
||||
<pre><code>app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Previously rendering of a collection via <em>partial()</em> would look something like this:</p>
|
||||
|
||||
<pre><code>this.partial('comment.html.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>Although this worked just fine, it was generally to verbose, the similar but new API
|
||||
looks like this, as <em>partial()</em> is <em>always</em> passed as a local variable:</p>
|
||||
|
||||
<pre><code>partial('comment.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>To make things even less verbose we can assume the extension when omitted:</p>
|
||||
|
||||
<pre><code>partial('comment', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:</p>
|
||||
|
||||
<pre><code>partial('comments', comments);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Redirecting">Redirecting</h3>
|
||||
|
||||
<p>Previously you would</p>
|
||||
|
||||
<pre><code>this.redirect('/somewhere');
|
||||
</code></pre>
|
||||
|
||||
<p>However you would now:</p>
|
||||
|
||||
<pre><code>res.redirect('/somewhere');
|
||||
res.redirect('/somewhere', 301);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="HTTP-Client">HTTP Client</h3>
|
||||
|
||||
<p>Previously Express provided a high level http client, this library is no more
|
||||
as it does not belong in Express, however it may be resurrected as a separate module.</p>
|
||||
|
||||
<h3 id="Core-Extensions">Core Extensions</h3>
|
||||
|
||||
<p>Express is no longer dependent on the <a href="http://github.com/visionmedia/ext.js">JavaScript Extensions</a> library, so those of you using the methods provided by it such as <code>Object.merge(a, b)</code> will need to
|
||||
roll your own, or install the module via:</p>
|
||||
|
||||
<pre><code>$ npm install ext
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
|
||||
### Built On Connect
|
||||
|
||||
Express 1.x is written to run on-top of the [Connect](http://extjs.github.com/Connect) middlware
|
||||
framework, thus the _Plugin_ has been replaced by Connect's middleware. By abstracting our middleware
|
||||
to Connect we allow additional community frameworks to develop robust, high-level frameworks using
|
||||
the same technologies as Express.
|
||||
|
||||
### Creating Applications
|
||||
|
||||
Previously due to legacy code implemented in the early days of node,
|
||||
Express unfortunately had some globals. The DSL would previously be
|
||||
accessed as shown below:
|
||||
|
||||
require('express');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get('/', function(){
|
||||
return 'hello world';
|
||||
});
|
||||
|
||||
Now we utilize the CommonJS module system appropriately, and
|
||||
introduce _express.createServer()_ which accepts the same arguments
|
||||
as _http.createServer()_:
|
||||
|
||||
var express = require('express'),
|
||||
app = express.createServer();
|
||||
|
||||
app.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
Express 1.x does _not_ currently allow returning of a string.
|
||||
|
||||
### Plugins vs Middleware
|
||||
|
||||
Previously Express was bundled with plugins, which were essentially what
|
||||
are now Connect middleware. Previously plugins would be utilized in a manor
|
||||
similar to below:
|
||||
|
||||
use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
|
||||
Which we can now _use()_ within our app, or pass to the _express.createServer()_ method:
|
||||
|
||||
var connect = require('connect');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.methodOverride(),
|
||||
connect.cookie()
|
||||
);
|
||||
|
||||
or:
|
||||
|
||||
var connect = require('connect');
|
||||
var app = express.createServer();
|
||||
|
||||
app.use('/', connect.logger());
|
||||
app.use('/', connect.methodOverride());
|
||||
app.use('/', connect.cookieDecoder());
|
||||
|
||||
For documentation on creating Connect middleware visit [Middleware Authoring](http://extjs.github.com/Connect/#Middleware-Authoring).
|
||||
|
||||
### Running Applications
|
||||
|
||||
Previously a global function _run()_, was available:
|
||||
|
||||
run();
|
||||
|
||||
The new _express.Server_ has the same API as _http.Server_,
|
||||
so we can do things like:
|
||||
|
||||
app.listen();
|
||||
app.listen(3000);
|
||||
|
||||
### Route Parameters
|
||||
|
||||
Previously we could use _this.param()_ to attempt
|
||||
fetching a route, query string, or request body parameter:
|
||||
|
||||
get('/user/:id', function(){
|
||||
this.param('id');
|
||||
});
|
||||
|
||||
Polymorphic parameter access can be done using `req.param()`:
|
||||
|
||||
app.get('/user/:id', function(){
|
||||
req.param('id');
|
||||
});
|
||||
|
||||
Route parameters are also passed as the third argument:
|
||||
|
||||
app.get('/user/:id', function(req, res, params){
|
||||
params.id;
|
||||
});
|
||||
|
||||
### Passing Route Control
|
||||
|
||||
Old express had a weak notion of route passing,
|
||||
which did not support async, and was never properly
|
||||
implemented for practical use:
|
||||
|
||||
get('/', function(){
|
||||
this.pass('/foobar');
|
||||
});
|
||||
|
||||
Now Express has access to Connect's _next()_ function,
|
||||
which is passed as the fourth and final argument. Calling _next()_ will
|
||||
pass control to the next _matching route_, or continue down the stack
|
||||
of Connect middleware.
|
||||
|
||||
app.get('/user/:id?', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user', function(){
|
||||
// ... respond
|
||||
});
|
||||
|
||||
### View Rendering
|
||||
|
||||
View filenames no longer take the form _NAME_._TYPE_._ENGINE_,
|
||||
the _Content-Type_ can be set via _res.contentType()_ or
|
||||
_res.header()_. For example what was previously _layout.html.haml_,
|
||||
should now be _layout.haml_.
|
||||
|
||||
Previously a view render looked something like this:
|
||||
|
||||
get('/', function(){
|
||||
this.render('index.html.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
We now have _res.render()_, however the options passed to [haml](http://github.com/visionmedia/haml.js), [jade](http://github.com/visionmedia/jade), and others
|
||||
remain the same.
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
Previously rendering of a collection via _partial()_ would look something like this:
|
||||
|
||||
this.partial('comment.html.haml', { collection: comments });
|
||||
|
||||
Although this worked just fine, it was generally to verbose, the similar but new API
|
||||
looks like this, as _partial()_ is _always_ passed as a local variable:
|
||||
|
||||
partial('comment.haml', { collection: comments });
|
||||
|
||||
To make things even less verbose we can assume the extension when omitted:
|
||||
|
||||
partial('comment', { collection: comments });
|
||||
|
||||
And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:
|
||||
|
||||
partial('comments', comments);
|
||||
|
||||
### Redirecting
|
||||
|
||||
Previously you would
|
||||
|
||||
this.redirect('/somewhere');
|
||||
|
||||
However you would now:
|
||||
|
||||
res.redirect('/somewhere');
|
||||
res.redirect('/somewhere', 301);
|
||||
|
||||
### HTTP Client
|
||||
|
||||
Previously Express provided a high level http client, this library is no more
|
||||
as it does not belong in Express, however it may be resurrected as a separate module.
|
||||
|
||||
### Core Extensions
|
||||
|
||||
Express is no longer dependent on the [JavaScript Extensions](http://github.com/visionmedia/ext.js) library, so those of you using the methods provided by it such as `Object.merge(a, b)` will need to
|
||||
roll your own, or install the module via:
|
||||
|
||||
$ npm install ext
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
var messages = [],
|
||||
utils = require('express/utils'),
|
||||
http = require('express/http')
|
||||
|
||||
configure(function(){
|
||||
use(Logger)
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(Cookie)
|
||||
use(Cache, { lifetime: (5).minutes, reapInterval: (1).minute })
|
||||
use(Session, { lifetime: (15).minutes, reapInterval: (1).minute })
|
||||
use(Static)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.pass('/chat')
|
||||
})
|
||||
|
||||
get('/chat', function(){
|
||||
var self = this
|
||||
Session.store.length(function(err, len){
|
||||
self.render('chat.html.haml', {
|
||||
locals: {
|
||||
title: 'Chat',
|
||||
messages: messages,
|
||||
name: self.session.name,
|
||||
usersOnline: len
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
post('/chat', function(){
|
||||
this.session.name = this.param('name')
|
||||
messages
|
||||
.push(utils.escape(this.param('name')) + ': ' + utils.escape(this.param('message'))
|
||||
.replace(/(http:\/\/[^\s]+)/g, '<a href="$1" target="express-chat">$1</a>')
|
||||
.replace(/:\)/g, '<img src="http://icons3.iconfinder.netdna-cdn.com/data/icons/ledicons/emoticon_smile.png">'))
|
||||
this.respond(200)
|
||||
})
|
||||
|
||||
get('/chat/messages', function(){
|
||||
var self = this,
|
||||
previousLength = messages.length,
|
||||
timer = setInterval(function(){
|
||||
if (messages.length > previousLength)
|
||||
self.contentType('json'),
|
||||
previousLength = messages.length,
|
||||
self.respond(200, JSON.encode(messages)),
|
||||
clearInterval(timer)
|
||||
}, 100)
|
||||
})
|
||||
|
||||
get('/*.css', function(file){
|
||||
this.render(file + '.css.sass', { layout: false })
|
||||
})
|
||||
|
||||
get('/error/view', function(){
|
||||
this.render('does.not.exist')
|
||||
})
|
||||
|
||||
get('/error', function(){
|
||||
throw new Error('oh noes!')
|
||||
})
|
||||
|
||||
get('/simple', function(){
|
||||
return 'Hello :)'
|
||||
})
|
||||
|
||||
get('/favicon.ico', function(){
|
||||
this.notFound()
|
||||
})
|
||||
|
||||
run()
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 5.2 KiB |
@@ -1,28 +0,0 @@
|
||||
|
||||
$(function(){
|
||||
// Send message
|
||||
$('form').submit(function(){
|
||||
var message = $('input[name=message]'),
|
||||
name = $('input[name=name]')
|
||||
if (message.val())
|
||||
$.post('/chat', { name: name.val(), message: message.val() }, function(){
|
||||
message.val('')
|
||||
})
|
||||
else
|
||||
message.css('border', '1px solid red')
|
||||
return false
|
||||
})
|
||||
|
||||
// Longpoll
|
||||
;(function poll(){
|
||||
$.getJSON('/chat/messages', function(messages){
|
||||
$('#messages').empty()
|
||||
$.each(messages, function(i, msg){
|
||||
$('#messages')
|
||||
.append('<li>' + msg + '</li>')
|
||||
.get(0).scrollTop = $('#messages').get(0).scrollHeight
|
||||
})
|
||||
poll()
|
||||
})
|
||||
})()
|
||||
})
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,9 +0,0 @@
|
||||
%h1 Chat
|
||||
%img.bubble{ src: '/public/images/bubble.png' }
|
||||
%ul#messages
|
||||
!= this.partial('message.html.haml', { collection: messages })
|
||||
%form{ method: 'post' }
|
||||
%input{ type: 'hidden', name: '_method', value: 'put' }
|
||||
%input{ type: 'text', name: 'name', value: name || 'guest' }
|
||||
%input{ type: 'text', name: 'message' }
|
||||
%input{ type: 'submit', value: 'Send' }
|
||||
@@ -1,12 +0,0 @@
|
||||
%html
|
||||
%head
|
||||
%title= title
|
||||
%script{ src: '/public/javascripts/jquery.js' }
|
||||
%script{ src: '/public/javascripts/app.js' }
|
||||
%link{ rel: 'stylesheet', href: '/style.css' }
|
||||
%body
|
||||
#wrapper
|
||||
!= body
|
||||
#online
|
||||
Online:
|
||||
%strong= usersOnline
|
||||
@@ -1 +0,0 @@
|
||||
%li= message
|
||||
@@ -1,81 +0,0 @@
|
||||
body
|
||||
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
|
||||
:font-size 13px
|
||||
:text-align center
|
||||
=text-stroke 1px rgba(255, 255, 255, 0.1)
|
||||
:color #555
|
||||
|
||||
h1, h2
|
||||
:margin 0
|
||||
:font-size 22px
|
||||
:color #343434
|
||||
h1
|
||||
:text-shadow 1px 2px 2px #ddd
|
||||
:font-size 60px
|
||||
|
||||
img.bubble
|
||||
:position absolute
|
||||
:top -25px
|
||||
:left 120px
|
||||
|
||||
#wrapper
|
||||
:position relative
|
||||
:margin 100px auto
|
||||
:width 500px
|
||||
:text-align left
|
||||
|
||||
ul
|
||||
:margin 0
|
||||
:padding 0
|
||||
:max-height 300px
|
||||
:overflow-x hidden
|
||||
li
|
||||
:margin 5px 0
|
||||
:padding 3px 8px
|
||||
:list-style none
|
||||
:border 1px solid #eee
|
||||
=border-radius 3px
|
||||
=border-radius 3px
|
||||
li:hover
|
||||
:cursor pointer
|
||||
:color #2E2E2E
|
||||
|
||||
input[type=text]
|
||||
:padding 5px
|
||||
:border 1px solid #ddd
|
||||
:outline none
|
||||
=border-radius 2px
|
||||
input[type=text]:focus
|
||||
:border-color #00C3FF
|
||||
|
||||
input[type=submit]
|
||||
=border-radius 2px
|
||||
=box-shadow 0 1px 2px #ddd
|
||||
:padding 6px 10px
|
||||
:border solid 1px #999
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
|
||||
:color #333
|
||||
:text-decoration none
|
||||
:cursor pointer
|
||||
:display inline-block
|
||||
:text-align center
|
||||
:text-shadow 0px 1px 1px #fff
|
||||
:line-height 1
|
||||
input[type=submit]:hover
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
|
||||
input[type=submit]:active
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
|
||||
input[name=name]
|
||||
:width 80px
|
||||
|
||||
a
|
||||
:color #1ABFF1
|
||||
=transition-property padding
|
||||
=transition-duration 0.15s
|
||||
a:hover
|
||||
:padding 0 5px
|
||||
a:hover:before
|
||||
:content 'visit: '
|
||||
|
||||
#online
|
||||
:font-size 12px
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
require.paths.unshift 'lib'
|
||||
require 'express'
|
||||
require 'express/plugins'
|
||||
|
||||
sys: require 'sys'
|
||||
|
||||
configure ->
|
||||
use MethodOverride
|
||||
use ContentLength
|
||||
use Cookie
|
||||
use Session
|
||||
use Flash
|
||||
use Logger
|
||||
use Static
|
||||
set 'root', __dirname
|
||||
set 'views', __dirname + '/../upload/views'
|
||||
|
||||
get '/', ->
|
||||
@redirect('/upload')
|
||||
|
||||
get '/upload', ->
|
||||
@render 'upload.html.haml', {
|
||||
locals: {
|
||||
flashes: @flash 'info'
|
||||
}
|
||||
}
|
||||
|
||||
post '/upload', ->
|
||||
@param('images').each (image) =>
|
||||
sys.puts image.filename + ' -> ' + image.tempfile
|
||||
@flash 'info', 'Uploaded ' + image.filename
|
||||
@redirect '/upload'
|
||||
|
||||
get '/*.css', (file) ->
|
||||
@render file + '.css.sass', { layout: no }
|
||||
|
||||
run()
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -0,0 +1,29 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' },
|
||||
{ name: 'ciaran', email: 'ciaranj@gmail.com' },
|
||||
{ name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users.ejs', {
|
||||
locals: {
|
||||
users: users
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -0,0 +1,3 @@
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Caught and passed down to the errorHandler middleware
|
||||
throw new Error('something broke!');
|
||||
});
|
||||
|
||||
app.get('/next', function(req, res, params, next){
|
||||
// We can also pass exceptions to next()
|
||||
next(new Error('oh no!'))
|
||||
});
|
||||
|
||||
// The errorHandler middleware in this case will dump exceptions to stderr
|
||||
// as well as show the stack trace in responses, currently handles text/plain,
|
||||
// text/html, and application/json responses to aid in development
|
||||
app.use('/', connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect'),
|
||||
sys = require('sys');
|
||||
|
||||
var app = express.createServer(
|
||||
// Here we use the bodyDecoder middleware
|
||||
// to parse urlencoded request bodies
|
||||
// which populates req.body
|
||||
connect.bodyDecoder(),
|
||||
|
||||
// The methodOverride middleware allows us
|
||||
// to set a hidden input of _method to an arbitrary
|
||||
// HTTP method to support app.put(), app.del() etc
|
||||
connect.methodOverride()
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// get ?name=foo
|
||||
var name = req.param('name') || '';
|
||||
|
||||
// Switch the button label based if we have a name
|
||||
var label = name ? 'Update' : 'Save';
|
||||
|
||||
// If we have a name, we are updating,
|
||||
// so add the hidden _method input
|
||||
res.send('<form method="post">'
|
||||
+ (name ? '<input type="hidden" value="put" name="_method" />' : '')
|
||||
+ 'Name: <input type="text" name="name" value="' + name + '" />'
|
||||
+ '<input type="submit" value="' + label + '" />'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res){
|
||||
// Typically here we would create a resource
|
||||
sys.puts('saved ' + req.body.name);
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
});
|
||||
|
||||
app.put('/', function(req, res){
|
||||
// Typically here we would update a resource
|
||||
sys.puts('updated ' + req.body.name);
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,103 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect'),
|
||||
http = require('http');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Expose our views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
/**
|
||||
* Request github json api `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function request(path, fn){
|
||||
var client = http.createClient(80, 'github.com'),
|
||||
req = client.request('GET', '/api/v2/json' + path, { Host: 'github.com' });
|
||||
req.addListener('response', function(res){
|
||||
res.body = '';
|
||||
res.addListener('data', function(chunk){ res.body += chunk; });
|
||||
res.addListener('end', function(){
|
||||
try {
|
||||
fn(null, JSON.parse(res.body));
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort repositories by watchers desc.
|
||||
*
|
||||
* @param {Array} repos
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function sort(repos){
|
||||
return repos.sort(function(a, b){
|
||||
if (a.watchers == b.watchers) return 0;
|
||||
if (a.watchers > b.watchers) return -1;
|
||||
if (a.watchers < b.watchers) return 1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tally up total watchers.
|
||||
*
|
||||
* @param {Array} repos
|
||||
* @return {Number}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function totalWatchers(repos) {
|
||||
return repos.reduce(function(sum, repo){
|
||||
return sum + repo.watchers;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default to my user name :)
|
||||
*/
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('/repos/visionmedia');
|
||||
});
|
||||
|
||||
/**
|
||||
* Display repos.
|
||||
*/
|
||||
|
||||
app.get('/repos/:user', function(req, res, params, next){
|
||||
var name = params.user;
|
||||
request('/repos/show/' + name, function(err, user){
|
||||
if (err) {
|
||||
next(err)
|
||||
} else {
|
||||
res.render('index.jade', {
|
||||
locals: {
|
||||
totalWatchers: totalWatchers(user.repositories),
|
||||
repos: sort(user.repositories),
|
||||
name: name
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Serve statics from ./public
|
||||
app.use('/', connect.staticProvider(__dirname + '/public'));
|
||||
|
||||
// Listen on port 3000
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,11 @@
|
||||
body {
|
||||
padding: 30px 50px;
|
||||
font: 12px/1.4 "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
|
||||
}
|
||||
a {
|
||||
color: #00AAFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
h1= name
|
||||
p.summary
|
||||
| <a href="http://github.com/#{name}">#{name}</a> has <strong>#{repos.length}</strong> repositories
|
||||
| with a total of <strong>#{totalWatchers}</strong> watchers.
|
||||
table#repos!= partial('repo', repos)
|
||||
@@ -0,0 +1,7 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Github Example
|
||||
link(rel="stylesheet", href="/style.css")
|
||||
body
|
||||
#container!= body
|
||||
@@ -0,0 +1,5 @@
|
||||
tr.repo
|
||||
td.name
|
||||
a(href: repo.homepage || repo.url)= repo.name
|
||||
td.watchers
|
||||
= repo.watchers
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
|
||||
configure(function(){
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.render('front.html.ejs', {
|
||||
locals: {
|
||||
title: 'Hello World',
|
||||
name: 'Joe',
|
||||
items: ['one', 'two', 'three']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
run()
|
||||
@@ -1,9 +0,0 @@
|
||||
<h1><%= title %></h1>
|
||||
<%= this.partial("greeting.html.ejs", { locals: { name: name } }) %>
|
||||
<% if (items && items.length) { %>
|
||||
<ul>
|
||||
<% for (var i = 0; i < items.length; ++i) { %>
|
||||
<li><%= items[i] %></li>
|
||||
<% } %>
|
||||
</ul>
|
||||
<% } %>
|
||||
@@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<%= body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
Welcome back, <strong><%= name %></strong>!
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect');
|
||||
|
||||
// Path to our public directory
|
||||
|
||||
var pub = __dirname + '/public';
|
||||
|
||||
// Auto-compile sass to css with "compiler"
|
||||
// and then serve with connect's staticProvider
|
||||
|
||||
var app = express.createServer(
|
||||
connect.compiler({ src: pub, enable: ['sass'] }),
|
||||
connect.staticProvider(pub)
|
||||
);
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Enable auto-reloading of view contents when changed
|
||||
// with an interval of 1000 milliseconds. Start the app
|
||||
// with $ node examples/jade/app.js
|
||||
// then alter some views :)
|
||||
|
||||
app.set('reload views', 1000);
|
||||
// or app.enable('reload views'); for defaults
|
||||
|
||||
// Re-compile
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' },
|
||||
{ name: 'ciaran', email: 'ciaranj@gmail.com' },
|
||||
{ name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users.jade', {
|
||||
locals: {
|
||||
users: users
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
padding: 50px 80px;
|
||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;}
|
||||
@@ -0,0 +1,3 @@
|
||||
body
|
||||
:padding 50px 80px
|
||||
:font 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif
|
||||
@@ -0,0 +1,6 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
body!= body
|
||||
@@ -0,0 +1,3 @@
|
||||
.user
|
||||
h2= user.name
|
||||
.email= user.email
|
||||
@@ -0,0 +1,3 @@
|
||||
- if (users.length)
|
||||
h1 Users
|
||||
#users!= partial('user', users)
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
form = require('./../../support/connect-form'),
|
||||
connect = require('connect'),
|
||||
sys = require('sys');
|
||||
|
||||
var app = express.createServer(
|
||||
// connect-form (http://github.com/visionmedia/connect-form)
|
||||
// middleware uses the formidable middleware to parse urlencoded
|
||||
// and multipart form data
|
||||
form()
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<form method="post" enctype="form-data/multipart">'
|
||||
+ '<p>Image: <input type="file" name="image" /></p>'
|
||||
+ '<p><input type="submit" value="Upload" /></p>'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res, params, next){
|
||||
|
||||
// connect-form adds the req.form object
|
||||
// we can (optionally) define onComplete, passing
|
||||
// the exception (if any) fields parsed, and files parsed
|
||||
req.form.complete(function(err, fields, files){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
sys.puts('\nuploaded ' + files.image.filename);
|
||||
res.redirect('back');
|
||||
}
|
||||
});
|
||||
|
||||
// We can add listeners for several form
|
||||
// events such as "progress"
|
||||
req.form.addListener('progress', function(bytesReceived, bytesExpected){
|
||||
var percent = (bytesReceived / bytesExpected * 100) | 0;
|
||||
sys.print('Uploading: %' + percent + '\r');
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer(),
|
||||
sys = require('sys');
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Provide our app with the notion of NotFound exceptions
|
||||
|
||||
function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
|
||||
// We can call app.error() several times as shown below.
|
||||
// Here we check for an instanceof NotFound and show the
|
||||
// 404 page, or we pass on to the next error handler.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Here we assume all errors as 500 for the simplicity of
|
||||
// this demo, however you can choose whatever you like
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1 @@
|
||||
h2 Page Not Found
|
||||
@@ -0,0 +1,2 @@
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
@@ -0,0 +1,8 @@
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
@@ -0,0 +1,6 @@
|
||||
html
|
||||
head
|
||||
title Custom Pages Example
|
||||
body
|
||||
h1 My Site
|
||||
!= body
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
var sys = require('sys')
|
||||
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(Cookie)
|
||||
use(Session)
|
||||
use(Flash)
|
||||
use(Logger)
|
||||
use(Static)
|
||||
set('root', __dirname)
|
||||
set('max upload size', (5).megabytes)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.redirect('/upload')
|
||||
})
|
||||
|
||||
get('/upload', function(){
|
||||
this.render('upload.html.haml', {
|
||||
locals: {
|
||||
flashes: this.flash('info')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
post('/upload', function(){
|
||||
this.param('images').each(function(image){
|
||||
sys.puts(image.filename + ' -> ' + image.tempfile)
|
||||
this.flash('info', 'Uploaded ' + image.filename)
|
||||
}, this)
|
||||
this.redirect('/upload')
|
||||
})
|
||||
|
||||
get('/*.css', function(file){
|
||||
this.render(file + '.css.sass', { layout: false })
|
||||
})
|
||||
|
||||
run()
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,13 +0,0 @@
|
||||
%html
|
||||
%head
|
||||
%title Upload
|
||||
%script{ src: '/public/javascripts/jquery.js' }
|
||||
%link{ rel: 'stylesheet', href: '/style.css' }
|
||||
%body
|
||||
#wrapper
|
||||
%h1 Upload
|
||||
- if (flashes)
|
||||
%ul.messages.info
|
||||
- each msg in flashes
|
||||
%li= msg
|
||||
.body!= body
|
||||
@@ -1,68 +0,0 @@
|
||||
body
|
||||
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
|
||||
:font-size 13px
|
||||
:text-align center
|
||||
:-webkit-text-stroke 1px rgba(255, 255, 255, 0.1)
|
||||
:color #555
|
||||
|
||||
h1, h2
|
||||
:margin 0 0 15px 0
|
||||
:font-size 22px
|
||||
:color #343434
|
||||
h1
|
||||
:text-shadow 1px 2px 2px #ddd
|
||||
:font-size 60px
|
||||
h2
|
||||
:margin-top 15px
|
||||
|
||||
#wrapper
|
||||
:position relative
|
||||
:margin 100px auto
|
||||
:width 500px
|
||||
:text-align left
|
||||
|
||||
input[type=file]
|
||||
:padding 5px
|
||||
:border 1px solid #ddd
|
||||
:outline none
|
||||
:-webkit-border-radius 2px
|
||||
:-moz-border-radius 2px
|
||||
input[type=file]:focus
|
||||
:border-color #00C3FF
|
||||
|
||||
input[type=submit]
|
||||
:-webkit-border-radius 2px
|
||||
:-moz-border-radius 2px
|
||||
:-webkit-box-shadow 0 1px 2px #ddd
|
||||
:-moz-box-shadow 0 1px 2px #ddd
|
||||
:padding 6px 10px
|
||||
:border solid 1px #999
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
|
||||
:color #333
|
||||
:text-decoration none
|
||||
:cursor pointer
|
||||
:display inline-block
|
||||
:text-align center
|
||||
:text-shadow 0px 1px 1px #fff
|
||||
:line-height 1
|
||||
input[type=submit]:hover
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
|
||||
input[type=submit]:active
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
|
||||
input[name=name]
|
||||
:width 80px
|
||||
|
||||
form
|
||||
.panel
|
||||
:float left
|
||||
:width 100%
|
||||
:margin-bottom 15px
|
||||
|
||||
.messages
|
||||
:margin 0
|
||||
:padding 0
|
||||
:border 1px solid #eee
|
||||
=box-shadow 2px 2px 5px #eee
|
||||
li
|
||||
:padding 5px 10px
|
||||
:list-style none
|
||||
@@ -1,17 +0,0 @@
|
||||
- if (typeof images !== 'undefined')
|
||||
.images
|
||||
- each img in images
|
||||
%img{ src: img }
|
||||
%h2 Singles
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[0]' }
|
||||
%input{ type: 'file', name: 'images[1]' }
|
||||
%input{ type: 'file', name: 'images[2]' }
|
||||
%div.panel
|
||||
%input{ type: 'submit', value: 'Upload' }
|
||||
|
||||
%h2 Multiple
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[]', multiple: 'multiple' }
|
||||
%div.panel
|
||||
%input{ type: 'submit', value: 'Upload' }
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
module.exports = require('./lib/express');
|
||||
Arquivo executável
+14
@@ -0,0 +1,14 @@
|
||||
|
||||
install() {
|
||||
mkdir -p /tmp/$2 \
|
||||
&& cd /tmp/$2 \
|
||||
&& echo "... installing $2" \
|
||||
&& curl -# -L "http://github.com/$1/$2/tarball/master" \
|
||||
| tar xz --strip 1 \
|
||||
&& cp -fr lib/$2 ~/.node_libraries/$2
|
||||
}
|
||||
|
||||
install visionmedia express \
|
||||
&& install senchalabs connect \
|
||||
&& cp -f /tmp/express/bin/express /usr/local/bin/express \
|
||||
&& echo "... installation complete"
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require.paths.unshift(__dirname + '/support/ext/lib')
|
||||
require.paths.unshift(__dirname + '/support/ejs/lib')
|
||||
require.paths.unshift(__dirname + '/support/haml/lib')
|
||||
require.paths.unshift(__dirname + '/support/sass/lib')
|
||||
require.paths.unshift(__dirname + '/support/multipart/lib')
|
||||
require('ext')
|
||||
Class = require('support/class/lib/class').Class
|
||||
require('express/core')
|
||||
@@ -1,327 +0,0 @@
|
||||
|
||||
// Express - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Request = require('express/request').Request,
|
||||
normalizePath = require('express/request').normalizePath,
|
||||
multipart = require('old'),
|
||||
utils = require('express/utils'),
|
||||
http = require('http'),
|
||||
sys = require('sys'),
|
||||
fs = require('fs')
|
||||
|
||||
Object.merge(global, require('express/plugin'))
|
||||
Object.merge(global, require('express/dsl'))
|
||||
|
||||
// --- Route
|
||||
|
||||
Route = new Class({
|
||||
|
||||
/**
|
||||
* Initialize a route with the given _method_,
|
||||
* _path_, and _callback_.
|
||||
*
|
||||
* The given _path_ becomes #originalPath,
|
||||
* #path is then a normalized version converted
|
||||
* to a regular expression for routing.
|
||||
*
|
||||
* @param {string} method
|
||||
* @param {string} path
|
||||
* @param {function} callback
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
constructor: function(method, path, callback, options){
|
||||
this.method = method
|
||||
this.originalPath = path
|
||||
this.path = this.normalize(path)
|
||||
this.callback = callback
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalize _path_. When a RegExp it is simply returned,
|
||||
* otherwise a string is converted to a regular expression
|
||||
* surrounded by ^$. So /user/:id/edit would become:
|
||||
*
|
||||
* /^\/user\/([^\/]+)\/edit$/i
|
||||
*
|
||||
* Each param key (:id) will be captured and placed in the
|
||||
* params array, so param('id') would give the string captured.
|
||||
*
|
||||
* The following are valid routes:
|
||||
*
|
||||
* - /user/:id Ex: '/user/12'
|
||||
* - /user/:id? Ex: '/user', '/user/12'
|
||||
* - /report.:format Ex: '/report.pdf', 'report.csv'
|
||||
* - /public/* Ex: '/public/app.js', '/public/javascripts/app.js'
|
||||
* - /public/*.* Ex: '/public/app.js', '/public/javascripts/app.js'
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {regexp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
normalize: function(path) {
|
||||
var self = this
|
||||
this.keys = []
|
||||
if (path instanceof RegExp) return path
|
||||
return new RegExp('^' + RegExp.escape(normalizePath(path), '.')
|
||||
.replace(/\*/g, '(.+)')
|
||||
.replace(/(\/|\\\.):(\w+)\?/g, function(_, c, key){
|
||||
self.keys.push(key)
|
||||
return '(?:' + c + '([^\/]+))?'
|
||||
})
|
||||
.replace(/:(\w+)/g, function(_, key){
|
||||
self.keys.push(key)
|
||||
return '([^\/]+)'
|
||||
}) + '$', 'i')
|
||||
}
|
||||
})
|
||||
|
||||
// --- Router
|
||||
|
||||
Router = new Class({
|
||||
|
||||
/**
|
||||
* Initialize with _request_ and parse url.
|
||||
*
|
||||
* @param {Request} request
|
||||
* @api private
|
||||
*/
|
||||
|
||||
constructor: function(request) {
|
||||
this.request = request
|
||||
this.method = request.method.lowercase
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluate the matched route against #request.
|
||||
*
|
||||
* @return {mixed}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
route: function() {
|
||||
var body,
|
||||
route = this.matchingRoute()
|
||||
if (route) {
|
||||
body = route.callback.apply(this.request, this.request.captures.slice(1));
|
||||
if (this.request.passed) {
|
||||
if (typeof this.request.passed === 'string')
|
||||
this.request.url.pathname = this.request.passed
|
||||
this.request.passed = false
|
||||
return this.route()
|
||||
}
|
||||
return body
|
||||
}
|
||||
else
|
||||
this.request.notFound()
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempt to match a route from Express.routes.
|
||||
*
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
matchingRoute: function() {
|
||||
this.lastMatchingRoute = this.lastMatchingRoute || 0
|
||||
var routes = Express.routes, route
|
||||
while (route = routes[this.lastMatchingRoute++])
|
||||
if (this.match(route))
|
||||
break
|
||||
return route
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if _route_ matches the current request.
|
||||
* If so populate #captures and #params.
|
||||
*
|
||||
* @param {object} route
|
||||
* @return {bool}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
match: function(route) {
|
||||
if (this.method === route.method)
|
||||
if (this.request.captures = this.request.url.pathname.match(route.path)) {
|
||||
this.mapParams(route)
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Map #request.captures to #request.params.path based on the
|
||||
* given _route_ params.
|
||||
*
|
||||
* @param {Route} route
|
||||
* @api private
|
||||
*/
|
||||
|
||||
mapParams: function(route) {
|
||||
route.keys.each(function(key, i){
|
||||
var val = this.request.captures[++i]
|
||||
if (key in Express.params)
|
||||
if ((val = Express.params[key].call(this.request, val)) === false)
|
||||
this.request.passed = true
|
||||
this.request.params.path[key] = this.request.captures[i] = val
|
||||
}, this)
|
||||
}
|
||||
})
|
||||
|
||||
// --- Server
|
||||
|
||||
Server = new Class({
|
||||
|
||||
/**
|
||||
* Default port number.
|
||||
*/
|
||||
|
||||
port: 3000,
|
||||
|
||||
/**
|
||||
* Default host ip, when null node will accept requests on
|
||||
* all network addresses.
|
||||
*/
|
||||
|
||||
host: null,
|
||||
|
||||
/**
|
||||
* Run Express with optional _port_ defaulting to 3000,
|
||||
* and host defaulting to null (INADDR_ANY).
|
||||
*
|
||||
* @param {int} port
|
||||
* @param {string} host
|
||||
* @return {Server}
|
||||
* @see run()
|
||||
* @api private
|
||||
*/
|
||||
|
||||
run: function(port, host){
|
||||
var self = this
|
||||
if (host !== undefined) this.host = host
|
||||
if (port !== undefined) this.port = port
|
||||
var server = http
|
||||
.createServer(function(req, response){
|
||||
var request, pendingFiles = 0
|
||||
req.setEncoding('binary')
|
||||
request = new Request(req, response)
|
||||
request.body = ''
|
||||
function callback(err) {
|
||||
if (err)
|
||||
request.error(err)
|
||||
else if (!pendingFiles)
|
||||
self.route(request)
|
||||
}
|
||||
if (request.header('Content-Type') &&
|
||||
request.header('Content-Type').includes('multipart/form-data')) {
|
||||
var stream,
|
||||
contentLength = parseInt(request.header('Content-Length')),
|
||||
maxBodyLength = set('max upload size')
|
||||
if (maxBodyLength && contentLength > maxBodyLength)
|
||||
return callback(new Error('upload size limit exceeded'))
|
||||
stream = multipart.parse(req)
|
||||
stream
|
||||
.addListener('partBegin', function(part) {
|
||||
if (part.filename)
|
||||
++pendingFiles,
|
||||
part.tempfile = '/tmp/express-' + Date.now() + utils.uid(),
|
||||
part.fileStream = fs.createWriteStream(part.tempfile),
|
||||
part.fileStream.addListener('error', callback)
|
||||
else
|
||||
part.buf = ''
|
||||
})
|
||||
.addListener('body', function(chunk) {
|
||||
if (stream.part.fileStream)
|
||||
stream.part.fileStream.write(chunk, 'binary')
|
||||
else
|
||||
stream.part.buf += chunk
|
||||
})
|
||||
.addListener('partEnd', function(part) {
|
||||
if (!part.name) return
|
||||
if (part.fileStream)
|
||||
part.fileStream.end(function(){
|
||||
--pendingFiles
|
||||
callback()
|
||||
}),
|
||||
utils.mergeParam(part.name, { filename: part.filename, tempfile: part.tempfile }, request.params.post)
|
||||
else
|
||||
utils.mergeParam(part.name, part.buf, request.params.post)
|
||||
})
|
||||
.addListener('error', callback)
|
||||
.addListener('complete', callback)
|
||||
}
|
||||
else
|
||||
req
|
||||
.addListener('data', function(chunk){ request.body += chunk })
|
||||
.addListener('end', callback)
|
||||
})
|
||||
server.listen(this.port, this.host)
|
||||
sys.puts('Express started at http://' + (this.host || '*') + ':' + this.port + '/ in ' + Express.environment + ' mode')
|
||||
return server
|
||||
},
|
||||
|
||||
/**
|
||||
* Route the given _request_.
|
||||
*
|
||||
* @param {Request} request
|
||||
* @api private
|
||||
*/
|
||||
|
||||
route: function(request){
|
||||
var self = this
|
||||
request.trigger('request', function(err) {
|
||||
try {
|
||||
if (err) throw err
|
||||
if (request.response.finished) return
|
||||
if (typeof (body = (new Router(request)).route()) === 'string')
|
||||
request.respond(200, body)
|
||||
} catch (err) {
|
||||
request.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// --- Express
|
||||
|
||||
Express = {
|
||||
version: '0.13.0',
|
||||
config: [],
|
||||
routes: [],
|
||||
plugins: [],
|
||||
settings: {},
|
||||
params: {},
|
||||
server: new Server
|
||||
}
|
||||
|
||||
// --- Defaults
|
||||
|
||||
configure(function(){
|
||||
use(require('express/plugins/view').View)
|
||||
use(require('express/plugins/cache').Cache)
|
||||
use(require('express/plugins/redirect').Redirect)
|
||||
use(require('express/plugins/body-decoder').BodyDecoder)
|
||||
})
|
||||
|
||||
configure('development', function(){
|
||||
enable('helpful 404')
|
||||
enable('show exceptions')
|
||||
enable('dump exceptions')
|
||||
})
|
||||
|
||||
configure('test', function(){
|
||||
enable('throw exceptions')
|
||||
disable('dump exceptions')
|
||||
})
|
||||
|
||||
configure('production', function(){
|
||||
enable('cache view contents')
|
||||
enable('cache view partials')
|
||||
enable('cache static files')
|
||||
})
|
||||
@@ -1,161 +0,0 @@
|
||||
|
||||
// Express - DSL - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Return a routing function for _method_.
|
||||
*
|
||||
* @param {string} method
|
||||
* @return {function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function route(method) {
|
||||
return function(path, options, callback){
|
||||
if (options instanceof Function)
|
||||
callback = options, options = {}
|
||||
Express.routes.push(new Route(method, path, callback, options))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set _option_ to _val_. When only _option_ is
|
||||
* present its current value will be returned.
|
||||
*
|
||||
* @param {string} option
|
||||
* @param {mixed} val
|
||||
* @return {mixed}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.set = function(option, val) {
|
||||
return val === undefined
|
||||
? Express.settings[option] instanceof Function
|
||||
? Express.settings[option]()
|
||||
: Express.settings[option]
|
||||
: Express.settings[option] = val
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable _options_.
|
||||
*
|
||||
* @param {string} option
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.enable = function(option) {
|
||||
set(option, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable _option_.
|
||||
*
|
||||
* @param {string} option
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.disable = function(option) {
|
||||
set(option, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Express, view Server#run() for parameters.
|
||||
*
|
||||
* All configuration handlers for EXPRESS_ENV or 'development'
|
||||
* are called before starting the server.
|
||||
*
|
||||
* @see Server#run()
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.run = function() {
|
||||
configure(Express.environment = process.env.EXPRESS_ENV || 'development')
|
||||
Express.plugins.each(function(plugin){
|
||||
if ('init' in plugin.klass)
|
||||
plugin.klass.init(plugin.options)
|
||||
})
|
||||
return Express.server.run.apply(Express.server, arguments)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure _env_ with _callback_.
|
||||
*
|
||||
* Global configuration, disregards which
|
||||
* environment is active:
|
||||
*
|
||||
* configure(function(){
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
* Environment specific configuration:
|
||||
*
|
||||
* configure('development', function(){
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
* Running configurations:
|
||||
*
|
||||
* configure('development')
|
||||
*
|
||||
* @param {string, function} env
|
||||
* @param {function} callback
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.configure = function(env, callback) {
|
||||
if (env instanceof Function)
|
||||
callback = env, env = 'all'
|
||||
if (callback instanceof Function)
|
||||
return Express.config.push([env, callback])
|
||||
if (typeof env !== 'string')
|
||||
throw new TypeError('environment required')
|
||||
Express.config.each(function(conf){
|
||||
if (conf[0] === env ||
|
||||
conf[0] === 'all')
|
||||
conf[1].call(Express)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process param _key_ with _callback_.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {function} callback
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.param = function(key, callback) {
|
||||
if (typeof key !== 'string')
|
||||
throw new TypeError('param key must be a string')
|
||||
if (typeof callback !== 'function')
|
||||
throw new TypeError('param must pass a function to process "' + key + '"')
|
||||
Express.params[key] = callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a "Not Found" route with the given _callback_.
|
||||
*
|
||||
* @param {function} callback
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.notFound = function(callback) {
|
||||
Express.notFound = callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an "error" route with the given _callback_.
|
||||
*
|
||||
* @param {function} callback
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.error = function(callback) {
|
||||
Express.error = callback
|
||||
}
|
||||
|
||||
// --- Routing API
|
||||
|
||||
exports.get = exports.view = route('get')
|
||||
exports.post = exports.create = route('post')
|
||||
exports.del = exports.destroy = route('delete')
|
||||
exports.put = exports.update = route('put')
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário