Compare commits

..

52 Commits

Author SHA1 Message Date
Tj Holowaychuk
52353da08b Release 1.0.2 2011-01-10 18:09:16 -08:00
Tj Holowaychuk
dc56b9b603 Removed nested require, using connect.router 2011-01-10 18:08:33 -08:00
Tj Holowaychuk
1446135545 docs 2011-01-03 13:33:51 -08:00
Tj Holowaychuk
cdc46307d7 Release 1.0.1 2010-12-29 11:38:02 -08:00
Tj Holowaychuk
dbf02c231a Fixed for middleware stacked via createServer() 2010-12-29 11:34:27 -08:00
Tj Holowaychuk
4732185e6f Fixed express(1) generated tests for express 0.7.0. Closes #484 2010-12-14 08:22:38 -08:00
Tj Holowaychuk
84a95b3101 Updated connect submodule 2010-12-06 14:54:50 -08:00
Tj Holowaychuk
09e8fe280b older expresso 2010-11-24 08:16:59 -08:00
Tj Holowaychuk
0e4ea9c16b Updated jade submodule 2010-11-24 08:14:44 -08:00
Tj Holowaychuk
c7542aef95 Merge branch 'master' into 1.x 2010-11-17 11:26:55 -08:00
Tj Holowaychuk
6873bce6c6 Merge branch 'master' into 1.x 2010-11-16 18:04:57 -08:00
Tj Holowaychuk
6ddacb6302 Merge branch 'master' into 1.x 2010-11-16 17:58:33 -08:00
Tj Holowaychuk
e1d33992a7 Merge branch 'master' into 1.x 2010-11-13 10:55:19 -08:00
Tj Holowaychuk
569c5139a6 Merge branch 'master' into 1.x 2010-11-12 08:46:07 -08:00
Tj Holowaychuk
6f5f5787e2 Merge branch 'master' into 1.x 2010-11-08 07:18:52 -08:00
Tj Holowaychuk
94cf769dd7 Merge branch 'master' into 1.x 2010-10-26 12:09:17 -07:00
Tj Holowaychuk
6d00b45eed Merge branch 'master' into 1.x 2010-10-26 01:18:24 -07:00
Tj Holowaychuk
6a4c6933aa Merge branch 'master' into 1.x 2010-10-22 16:20:47 -07:00
Tj Holowaychuk
c35ee2427e Merge branch 'master' into 1.x 2010-10-21 19:53:39 -07:00
Tj Holowaychuk
3d7216935a Merge branch 'master' into 1.x 2010-10-20 10:07:54 -07:00
Tj Holowaychuk
fc15c3d02b Merge branch 'master' into 1.x 2010-10-19 17:19:39 -07:00
Tj Holowaychuk
9eaec5b34e Merge branch 'master' into 1.x 2010-10-19 17:03:18 -07:00
Tj Holowaychuk
30712fa9d9 Merge branch 'master' into 1.x 2010-10-19 15:03:02 -07:00
Tj Holowaychuk
b817579d8a Merge branch 'master' into 1.x 2010-10-19 09:20:23 -07:00
Tj Holowaychuk
cbcaba3cec Merge branch 'master' into 1.x 2010-10-15 10:02:29 -07:00
Tj Holowaychuk
4e11fef43b Merge branch 'master' into 1.x 2010-10-15 08:26:04 -07:00
Tj Holowaychuk
067fdd5c4c Merge branch 'master' into 1.x 2010-10-14 09:08:19 -07:00
Tj Holowaychuk
fff815f666 Merge branch 'master' into 1.x 2010-10-14 04:17:19 -07:00
Tj Holowaychuk
609c18aa5b Merge branch 'master' into 1.x 2010-10-14 03:50:56 -07:00
Tj Holowaychuk
73c108ce90 Merge branch 'master' into 1.x 2010-10-14 03:03:24 -07:00
Tj Holowaychuk
1e9da205a7 Merge branch 'master' into 1.x 2010-10-12 12:59:14 -07:00
Tj Holowaychuk
d5539c7beb Merge branch 'master' into 1.x 2010-10-12 08:46:48 -07:00
Tj Holowaychuk
f87bd8c38f Merge branch 'master' into 1.x 2010-10-11 08:37:49 -07:00
Tj Holowaychuk
05515fa09e Merge branch 'master' into 1.x 2010-10-11 08:18:01 -07:00
Tj Holowaychuk
35c91ed6f5 Merge branch 'master' into 1.x 2010-10-08 11:39:14 -07:00
Tj Holowaychuk
26238c429d Merge branch 'master' into 1.x 2010-10-07 06:35:27 -07:00
Tj Holowaychuk
1b28ad16d4 Merge branch 'master' into 1.x 2010-10-07 05:46:45 -07:00
Tj Holowaychuk
e29f3aa5dd Merge branch 'master' into 1.x 2010-10-07 03:50:02 -07:00
Tj Holowaychuk
5c94603787 Merge branch 'master' into 1.x 2010-10-07 02:36:41 -07:00
Tj Holowaychuk
9409107f77 Merge branch 'master' into 1.x 2010-10-06 08:26:29 -07:00
Tj Holowaychuk
7f11aa25ea Merge branch 'master' into 1.x 2010-10-05 06:32:50 -07:00
Tj Holowaychuk
1994f24d82 Merge branch 'master' into 1.x 2010-10-04 11:16:56 -07:00
Tj Holowaychuk
b5b30a3f20 Merge branch 'master' into 1.x 2010-10-04 11:06:33 -07:00
Tj Holowaychuk
4fcbb961eb Merge branch 'master' into 1.x 2010-10-04 08:04:12 -07:00
Tj Holowaychuk
11cfad755a Merge branch 'master' into 1.x 2010-10-04 08:01:30 -07:00
Tj Holowaychuk
0b24bd08c9 Merge branch 'master' into 1.x 2010-10-01 16:33:34 -07:00
Tj Holowaychuk
b377839538 Merge branch 'master' into 1.x 2010-10-01 16:31:40 -07:00
Tj Holowaychuk
698d82f799 Merge branch 'master' into 1.x 2010-10-01 07:34:14 -07:00
Tj Holowaychuk
462a291eb8 Merge branch 'master' into 1.x 2010-09-23 09:37:05 -07:00
Tj Holowaychuk
79dc2467f7 Merge branch 'master' into 1.x 2010-09-22 16:09:15 -07:00
Tj Holowaychuk
0a0c86813d Merge branch 'master' into 1.x 2010-09-22 12:03:42 -07:00
Tj Holowaychuk
dfdc939816 Multipart typo 2010-09-21 12:39:14 -07:00
370 changed files with 14392 additions and 25975 deletions

View File

@@ -1,11 +0,0 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[{*.js,*.json,*.yml}]
indent_size = 2
indent_style = space

View File

@@ -1,2 +0,0 @@
coverage
node_modules

View File

@@ -1,14 +0,0 @@
root: true
env:
es2022: true
node: true
rules:
eol-last: error
eqeqeq: [error, allow-null]
indent: [error, 2, { MemberExpression: "off", SwitchCase: 1 }]
no-trailing-spaces: error
no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: true }]
no-restricted-globals:
- error
- name: Buffer
message: Use `import { Buffer } from "node:buffer"` instead of the global Buffer.

View File

@@ -1,17 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
- package-ecosystem: npm
directory: /
schedule:
interval: monthly
time: "23:00"
timezone: Europe/London
open-pull-requests-limit: 10
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

View File

@@ -1,117 +0,0 @@
name: ci
on:
push:
branches:
- master
- develop
- '4.x'
- '5.x'
- '5.0'
paths-ignore:
- '*.md'
pull_request:
workflow_dispatch:
permissions:
contents: read
# Cancel in progress workflows
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
concurrency:
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm install --ignore-scripts --include=dev
- name: Run lint
run: npm run lint
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 19, 20, 21, 22, 23, 24, 25]
# Node.js release schedule: https://nodejs.org/en/about/releases/
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{ matrix.node-version }}
- name: Configure npm loglevel
run: |
npm config set loglevel error
shell: bash
- name: Install dependencies
run: npm install
- name: Output Node and NPM versions
run: |
echo "Node.js version: $(node -v)"
echo "NPM version: $(npm -v)"
- name: Run tests
shell: bash
run: npm run test-ci
- name: Upload code coverage
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
path: ./coverage/lcov.info
retention-days: 1
coverage:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: Install lcov
shell: bash
run: sudo apt-get -y install lcov
- name: Collect coverage reports
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
path: ./coverage
pattern: coverage-node-*
- name: Merge coverage reports
shell: bash
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
- name: Upload coverage report
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
file: ./lcov.info

View File

@@ -1,74 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: ["master"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
schedule:
- cron: "0 0 * * 1"
workflow_dispatch:
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [javascript, actions]
steps:
- name: Checkout repository
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5
with:
languages: ${{ matrix.language }}
config: |
paths-ignore:
- test
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5

View File

@@ -1,101 +0,0 @@
name: legacy
on:
push:
branches:
- master
- develop
- '4.x'
- '5.x'
- '5.0'
paths-ignore:
- '*.md'
pull_request:
paths-ignore:
- '*.md'
workflow_dispatch:
permissions:
contents: read
# Cancel in progress workflows
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
concurrency:
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [16, 17]
# Node.js release schedule: https://nodejs.org/en/about/releases/
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{ matrix.node-version }}
- name: Configure npm loglevel
run: |
npm config set loglevel error
shell: bash
- name: Install dependencies
run: npm install
- name: Output Node and NPM versions
run: |
echo "Node.js version: $(node -v)"
echo "NPM version: $(npm -v)"
- name: Run tests
shell: bash
run: npm run test-ci
- name: Upload code coverage
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
path: ./coverage/lcov.info
retention-days: 1
coverage:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: Install lcov
shell: bash
run: sudo apt-get -y install lcov
- name: Collect coverage reports
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
path: ./coverage
pattern: coverage-node-*
- name: Merge coverage reports
shell: bash
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
- name: Upload coverage report
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
file: ./lcov.info

View File

@@ -1,14 +0,0 @@
name: Publish package to npm
on:
release:
types: [created]
permissions:
id-token: write
contents: read
jobs:
publish:
uses: expressjs/ci-workflows/.github/workflows/release.yml@main
secrets:
NPM_PUBLISH: ${{ secrets.NPM_PUBLISH }}

View File

@@ -1,72 +0,0 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '16 21 * * 1'
push:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5
with:
sarif_file: results.sarif

27
.gitignore vendored
View File

@@ -1,20 +1,9 @@
# npm
node_modules
package-lock.json
npm-shrinkwrap.json
.DS_Store
lib-cov
*.seed
*.log
*.gz
# Yarn
yarn-error.log
yarn.lock
# Coveralls
.nyc_output
coverage
# Benchmarking
benchmarks/graphs
# ignore additional files using core.excludesFile
# https://git-scm.com/docs/gitignore
*.csv
*.dat
*.out
*.pid
benchmarks/graphs

18
.gitmodules vendored Normal file
View File

@@ -0,0 +1,18 @@
[submodule "support/expresso"]
path = support/expresso
url = git://github.com/visionmedia/expresso.git
[submodule "support/haml"]
path = support/haml
url = git://github.com/visionmedia/haml.js.git
[submodule "support/ejs"]
path = support/ejs
url = git://github.com/visionmedia/ejs.git
[submodule "support/connect-form"]
path = support/connect-form
url = git://github.com/visionmedia/connect-form.git
[submodule "support/connect"]
path = support/connect
url = git://github.com/senchalabs/connect.git
[submodule "support/jade"]
path = support/jade
url = git://github.com/visionmedia/jade.git

1
.npmrc
View File

@@ -1 +0,0 @@
package-lock=false

3493
History.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,6 @@
(The MIT License)
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
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
@@ -21,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

76
Makefile Normal file
View File

@@ -0,0 +1,76 @@
PREFIX ?= /usr/local
LIB_PREFIX = ~/.node_libraries
DOCS = docs/index.md \
docs/executable.md \
docs/contrib.md \
docs/guide.md \
docs/migrate.md \
docs/applications.md
MANPAGES =$(DOCS:.md=.1)
HTMLDOCS =$(DOCS:.md=.html)
install: install-docs
@mkdir -p $(PREFIX)/bin
@mkdir -p $(LIB_PREFIX)
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
uninstall-support:
cd support/connect && $(MAKE) uninstall
install-docs:
@mkdir -p $(PREFIX)/share/man/man1
cp -f docs/executable.1 $(PREFIX)/share/man/man1/express.1
uninstall-docs:
rm -f $(PREFIX)/share/man/man1/express.1
test:
@NODE_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
docs: docs/api.html $(MANPAGES) $(HTMLDOCS)
@ echo "... generating TOC"
@./support/toc.js docs/guide.html
docs/api.html: lib/express/*.js
dox \
--private \
--title Express \
--desc "High performance web framework for [node](http://nodejs.org)." \
$(shell find lib/express/* -type f) > $@
%.1: %.md
@echo "... $< -> $@"
@ronn -r --pipe $< > $@
%.html: %.md
@echo "... $< -> $@"
@ronn -5 --pipe --fragment $< \
| cat docs/layout/head.html - docs/layout/foot.html \
| sed 's/NAME/Express/g' \
> $@
docclean:
rm -f docs/*.{1,html}
.PHONY: install uninstall install-docs install-support uninstall-support install-docs uninstall-docs test test-cov docs docclean

316
Readme.md
View File

@@ -1,277 +1,103 @@
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)
**Fast, unopinionated, minimalist web framework for [Node.js](https://nodejs.org).**
# Express
Insanely fast (and small) server-side JavaScript web development framework
built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect).
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World');
});
**This project has a [Code of Conduct].**
## Table of contents
- [Table of contents](#table-of-contents)
- [Installation](#installation)
- [Features](#features)
- [Docs \& Community](#docs--community)
- [Quick Start](#quick-start)
- [Philosophy](#philosophy)
- [Examples](#examples)
- [Contributing](#contributing)
- [Security Issues](#security-issues)
- [Running Tests](#running-tests)
- [Current project team members](#current-project-team-members)
- [TC (Technical Committee)](#tc-technical-committee)
- [TC emeriti members](#tc-emeriti-members)
- [Triagers](#triagers)
- [Emeritus Triagers](#emeritus-triagers)
- [License](#license)
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
[![Linux Build][github-actions-ci-image]][github-actions-ci-url]
[![Test Coverage][coveralls-image]][coveralls-url]
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
```js
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000')
})
```
app.listen(3000);
## Installation
This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/).
npm:
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
Node.js 18 or higher is required.
$ npm install express
If this is a brand new project, make sure to create a `package.json` first with
the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
curl:
Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
```bash
npm install express
```
Follow [our installing guide](https://expressjs.com/en/starter/installing.html)
for more information.
$ curl -# http://expressjs.com/install.sh | sh
## Features
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Redirection helpers
* Dynamic view helpers
* Content negotiation
* Focus on high performance
* View rendering and partials support
* Environment based configuration
* Session based flash notifications
* Built on [Connect](http://github.com/senchalabs/connect)
* High test coverage
* Executable for generating applications quickly
* Application level view options
## Docs & Community
Via Connect:
* [Website and Documentation](https://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
* [Github Discussions](https://github.com/expressjs/discussions) for discussion on the development and usage of Express
* Session support
* Cache API
* Mime helpers
* ETag support
* Persistent flash notifications
* Cookie support
* JSON-RPC
* Logging
* and _much_ more!
**PROTIP** Be sure to read the [migration guide to v5](https://expressjs.com/en/guide/migrating-5)
## Contributors
## Quick Start
The following are the major contributors of Express (in no specific order).
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
* Guillermo Rauch ([guille](http://github.com/guille))
Install the executable. The executable's major version will match Express's:
## More Information
```bash
npm install -g express-generator@4
```
* Express [Contrib](http://github.com/visionmedia/express-contrib) repo for additional functionality
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
Create the app:
## Node Compatibility
The latest release of Express is compatible with node --version:
```bash
express /tmp/foo && cd /tmp/foo
```
v0.2.5
Install dependencies:
and connect --version:
```bash
npm install
```
0.3.0
Start the server:
Express 1.x is maintained in the _1.x_ branch.
```bash
npm start
```
## License
View the website at: http://localhost:3000
(The MIT License)
## Philosophy
Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
The Express philosophy is to provide small, robust tooling for HTTP servers, making
it a great solution for single page applications, websites, hybrids, or public
HTTP APIs.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [@ladjs/consolidate](https://github.com/ladjs/consolidate),
you can quickly craft your perfect framework.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
## Examples
To view the examples, clone the Express repository:
```bash
git clone https://github.com/expressjs/express.git --depth 1 && cd express
```
Then install the dependencies:
```bash
npm install
```
Then run whichever example you want:
```bash
node examples/content-negotiation
```
## Contributing
The Express.js project welcomes all constructive contributions. Contributions take many forms,
from code for bug fixes and enhancements, to additions and fixes to documentation, additional
tests, triaging incoming pull requests and issues, and more!
See the [Contributing Guide] for more technical details on contributing.
### Security Issues
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](SECURITY.md).
### Running Tests
To run the test suite, first install the dependencies:
```bash
npm install
```
Then run `npm test`:
```bash
npm test
```
## Current project team members
For information about the governance of the express.js project, see [GOVERNANCE.md](https://github.com/expressjs/discussions/blob/HEAD/docs/GOVERNANCE.md).
The original author of Express is [TJ Holowaychuk](https://github.com/tj)
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
### TC (Technical Committee)
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd**
* [LinusU](https://github.com/LinusU) - **Linus Unnebäck**
* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [crandmck](https://github.com/crandmck) - **Rand McKinney**
* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida**
<details>
<summary>TC emeriti members</summary>
#### TC emeriti members
* [dougwilson](https://github.com/dougwilson) - **Douglas Wilson**
* [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa**
* [jonathanong](https://github.com/jonathanong) - **jongleberry**
* [niftylettuce](https://github.com/niftylettuce) - **niftylettuce**
* [troygoode](https://github.com/troygoode) - **Troy Goode**
</details>
### Triagers
* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
* [bjohansebas](https://github.com/bjohansebas) - **Sebastian Beltran**
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
* [Phillip9587](https://github.com/Phillip9587) - **Phillip Barta**
* [efekrskl](https://github.com/efekrskl) - **Efe Karasakal**
* [rxmarbles](https://github.com/rxmarbles) - **Rick Markins** (he/him)
<details>
<summary>Triagers emeriti members</summary>
#### Emeritus Triagers
* [AuggieH](https://github.com/AuggieH) - **Auggie Hudak**
* [G-Rath](https://github.com/G-Rath) - **Gareth Jones**
* [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi**
* [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi**
* [NotMoni](https://github.com/NotMoni) - **Moni**
* [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan**
* [davidmashe](https://github.com/davidmashe) - **David Ashe**
* [digitaIfabric](https://github.com/digitaIfabric) - **David**
* [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner**
* [fed135](https://github.com/fed135) - **Frederic Charette**
* [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim**
* [getspooky](https://github.com/getspooky) - **Yasser Ameur**
* [ghinks](https://github.com/ghinks) - **Glenn**
* [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed**
* [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil**
* [jake32321](https://github.com/jake32321) - **Jake Reed**
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [lekanikotun](https://github.com/lekanikotun) - **Troy Goode**
* [marsonya](https://github.com/marsonya) - **Lekan Ikotun**
* [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson**
* [maxakuru](https://github.com/maxakuru) - **Max Edell**
* [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings**
* [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav**
* [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe**
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
* [0ss](https://github.com/0ss) - **Salah**
* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
* [dpopp07](https://github.com/dpopp07) - **Dustin Popp**
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
</details>
## License
[MIT](LICENSE)
[coveralls-image]: https://img.shields.io/coverallsCoverage/github/expressjs/express?branch=master
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
[github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/expressjs/express/ci.yml?branch=master&label=ci
[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
[npm-downloads-image]: https://img.shields.io/npm/dm/express
[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
[npm-url]: https://npmjs.org/package/express
[npm-version-image]: https://img.shields.io/npm/v/express
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
[Code of Conduct]: https://github.com/expressjs/.github/blob/HEAD/CODE_OF_CONDUCT.md
[Contributing Guide]: https://github.com/expressjs/.github/blob/HEAD/CONTRIBUTING.md
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,56 +0,0 @@
# Security Policies and Procedures
This document outlines security procedures and general policies for the Express
project.
* [Reporting a Bug](#reporting-a-bug)
* [Disclosure Policy](#disclosure-policy)
* [Comments on this Policy](#comments-on-this-policy)
## Reporting a Bug
The Express team and community take all security bugs in Express seriously.
Thank you for improving the security of Express. We appreciate your efforts and
responsible disclosure and will make every effort to acknowledge your
contributions.
Report security bugs by emailing `express-security@lists.openjsf.org`.
To ensure the timely response to your report, please ensure that the entirety
of the report is contained within the email body and not solely behind a web
link or an attachment.
The lead maintainer will acknowledge your email within 48 hours, and will send a
more detailed response within 48 hours indicating the next steps in handling
your report. After the initial reply to your report, the security team will
endeavor to keep you informed of the progress towards a fix and full
announcement, and may ask for additional information or guidance.
Report security bugs in third-party modules to the person or team maintaining
the module.
## Pre-release Versions
Alpha and Beta releases are unstable and **not suitable for production use**.
Vulnerabilities found in pre-releases should be reported according to the [Reporting a Bug](#reporting-a-bug) section.
Due to the unstable nature of the branch it is not guaranteed that any fixes will be released in the next pre-release.
## Disclosure Policy
When the security team receives a security bug report, they will assign it to a
primary handler. This person will coordinate the fix and release process,
involving the following steps:
* Confirm the problem and determine the affected versions.
* Audit code to find any potential similar problems.
* Prepare fixes for all releases still under maintenance. These fixes will be
released as fast as possible to npm.
## The Express Threat Model
We are currently working on a new version of the security model, the most updated version can be found [here](https://github.com/expressjs/security-wg/blob/main/docs/ThreatModel.md)
## Comments on this Policy
If you have suggestions on how this process could be improved please submit a
pull request.

View File

@@ -1,17 +0,0 @@
all:
@./run 1 middleware 50
@./run 5 middleware 50
@./run 10 middleware 50
@./run 15 middleware 50
@./run 20 middleware 50
@./run 30 middleware 50
@./run 50 middleware 50
@./run 100 middleware 50
@./run 10 middleware 100
@./run 10 middleware 250
@./run 10 middleware 500
@./run 10 middleware 1000
@echo
.PHONY: all

View File

@@ -1,34 +0,0 @@
# Express Benchmarks
## Installation
You will need to install [wrk](https://github.com/wg/wrk/blob/master/INSTALL) in order to run the benchmarks.
## Running
To run the benchmarks, first install the dependencies `npm i`, then run `make`
The output will look something like this:
```
50 connections
1 middleware
7.15ms
6784.01
[...redacted...]
1000 connections
10 middleware
139.21ms
6155.19
```
### Tip: Include Node.js version in output
You can use `make && node -v` to include the node.js version in the output.
### Tip: Save the results to a file
You can use `make > results.log` to save the results to a file `results.log`.

View File

@@ -1,20 +0,0 @@
var express = require('..');
var app = express();
// number of middleware
var n = parseInt(process.env.MW || '1', 10);
console.log(' %s middleware', n);
while (n--) {
app.use(function(req, res, next){
next();
});
}
app.use(function(req, res){
res.send('Hello World')
});
app.listen(3333);

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
echo
MW=$1 node $2 &
pid=$!
echo " $3 connections"
sleep 2
wrk 'http://localhost:3333/?foo[bar]=baz' \
-d 3 \
-c $3 \
-t 8 \
| grep 'Requests/sec\|Latency' \
| awk '{ print " " $2 }'
kill $pid

426
bin/express Executable file
View File

@@ -0,0 +1,426 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var fs = require('fs')
, sys = require('sys')
, exec = require('child_process').exec;
/**
* Framework version.
*/
var version = '1.0.2';
/**
* stdin stream.
*/
var stdin;
/**
* Add session support.
*/
var sessions = false;
/**
* CSS engine to utilize.
*/
var cssEngine;
/**
* Template engine to utilize.
*/
var templateEngine = 'jade';
/**
* Usage documentation.
*/
var usage = ''
+ '\x1b[1mUsage\x1b[0m: express [options] [PATH]\n'
+ '\n'
+ '\x1b[1mOptions\x1b[0m:\n'
+ ' -s, --sessions Add session support\n'
+ ' -t, --template ENGINE Add template ENGINE support (jade|ejs). Defaults to jade\n'
+ ' -c, --css ENGINE Add stylesheet ENGINE support (less|sass). Defaults to plain css\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');
/**
* Jade index template.
*/
var jadeIndex = [
'h1= title'
, 'p Welcome to #{title}'
].join('\n');
/**
* EJS layout template.
*/
var ejsLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title><%= title %></title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <%- body %>'
, ' </body>'
, '</html>'
].join('\n');
/**
* EJS index template.
*/
var ejsIndex = [
'<h1><%= title %></h1>'
, '<p>Welcome to <%= title %></p>'
].join('\n');
/**
* Default css template.
*/
var css = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
].join('\n');
/**
* Default less template.
*/
var less = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
].join('\n');
/**
* Default sass template.
*/
var sass = [
'body'
, ' :padding 50px'
, ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
].join('\n');
/**
* App test template.
*/
var appTest = [
""
, "// Run $ expresso"
, ""
, "/**"
, " * Module dependencies."
, " */"
, ""
, "var app = require('../app')"
, " , assert = require('assert');"
, "",
, "module.exports = {"
, " 'GET /': function(){"
, " assert.response(app,"
, " { url: '/' },"
, " { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }},"
, " function(res){"
, " assert.includes(res.body, '<title>Express</title>');"
, " });"
, " }"
, "};"
].join('\n');
/**
* App template.
*/
var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\');'
, ''
, 'var app = module.exports = express.createServer();'
, ''
, '// Configuration'
, ''
, 'app.configure(function(){'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \':TEMPLATE\');'
, ' app.use(express.bodyDecoder());'
, ' app.use(express.methodOverride());:SESS:CSS'
, ' app.use(app.router);'
, ' app.use(express.staticProvider(__dirname + \'/public\'));'
, '});'
, ''
, 'app.configure(\'development\', function(){'
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
, '});'
, ''
, 'app.configure(\'production\', function(){'
, ' app.use(express.errorHandler()); '
, '});'
, ''
, '// Routes'
, ''
, 'app.get(\'/\', function(req, res){'
, ' res.render(\'index\', {'
, ' locals: {'
, ' title: \'Express\''
, ' }'
, ' });'
, '});'
, ''
, '// Only listen on $ node app.js'
, ''
, 'if (!module.parent) {'
, ' app.listen(3000);'
, ' console.log("Express server listening on port %d", app.address().port)'
, '}'
, ''
].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;
case '-s':
case '--session':
case '--sessions':
sessions = true;
break;
case '-c':
case '--css':
args.length
? (cssEngine = args.shift())
: abort('--css requires an argument');
break;
case '-t':
case '--template':
args.length
? (templateEngine = args.shift())
: abort('--template requires an argument');
break;
default:
path = arg;
}
}
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty) {
createApplicationAt(path);
} else {
confirm('destination is not empty, continue? ', function(ok){
if (ok) {
stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);
/**
* Create application at the given directory `path`.
*
* @param {String} path
*/
function createApplicationAt(path) {
mkdir(path, function(){
mkdir(path + '/pids');
mkdir(path + '/logs');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (cssEngine) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'sass':
write(path + '/public/stylesheets/style.sass', sass);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/views/partials', function(){
switch (templateEngine) {
case 'ejs':
write(path + '/views/layout.ejs', ejsLayout);
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
}
});
mkdir(path + '/test', function(){
write(path + '/test/app.test.js', appTest);
});
// CSS Engine support
switch (cssEngine) {
case 'sass':
case 'less':
app = app.replace(':CSS', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
break;
default:
app = app.replace(':CSS', '');
}
// Session support
app = app.replace(':SESS', sessions
? '\n app.use(express.cookieDecoder());\n app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', templateEngine);
write(path + '/app.js', app);
// Suggestions
process.on('exit', function(){
if (cssEngine) {
console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
, cssEngine
, cssEngine);
}
console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
, templateEngine
, templateEngine);
});
});
}
/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/
function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && err.errno !== process.ENOENT) throw err;
fn(!files || !files.length);
});
}
/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/
function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[33mcreate\x1b[0m : ' + path);
}
/**
* Prompt confirmation with the given `msg`.
*
* @param {String} msg
* @param {Function} fn
*/
function confirm(msg, fn) {
prompt(msg, function(val){
fn(/^ *y(es)?/i.test(val));
});
}
/**
* Prompt input with the given `msg` and callback `fn`.
*
* @param {String} msg
* @param {Function} fn
*/
function prompt(msg, fn) {
stdin = stdin || process.openStdin();
sys[msg[msg.length - 1] == ' ' ? 'print' : 'puts'](msg);
stdin.setEncoding('ascii');
stdin.addListener('data', function(data){
fn(data);
stdin.removeListener('data', arguments.callee);
});
}
/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/
function mkdir(path, fn) {
exec('mkdir -p ' + path, function(err){
if (err) throw err;
console.log(' \x1b[33mcreate\x1b[0m : ' + path);
fn && fn();
});
}
/**
* Exit with the given `str`.
*
* @param {String} str
*/
function abort(str) {
console.error(str);
process.exit(1);
}

1676
docs/api.html Normal file

File diff suppressed because it is too large Load Diff

70
docs/applications.1 Normal file
View File

@@ -0,0 +1,70 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "APPLICATIONS" "" "October 2010" "" ""
.
.SH "NAME"
\fBapplications\fR
.
.P
Learnboost \fIhttp://learnboost\.com\fR is a free online gradebook application, aimed to crush the competition with innovative, realtime, enjoyable features\.
.
.P
\fIhttp://learnboost\.com\fR
.
.P
Storify \fIhttp://storify\.com\fR lets you turn what people post on social media websites into compelling stories\.
.
.P
\fIhttp://storify\.com\fR
.
.P
Pakistan Survey \fIhttp://pakistansurvey\.org/\fR by Development Seed \fIhttp://developmentseed\.org\fR, provides in\-depth agency\-specific analysis from regional experts with data from 1,000 interviews across 120 villages in all seven tribal agencies and mapping of 142 reported drone strikes in FATA through July 2010\.
.
.P
\fIhttp://pakistansurvey\.org\fR
.
.P
Markup\.IO \fIhttp://markup\.io\fR allows you to draw directly on \fIany\fR website, then share with others to share your thoughts\.
.
.P
\fIhttp://markup\.io\fR
.
.P
Scrabb\.ly \fIhttp://scrabb\.ly\fR is a massively multiplayer scrabble game initially created for the Node Knockout \fIhttp://nodeknockout\.com/\fR competition\.
.
.P
\fIhttp://scrabb\.ly\fR
.
.P
ClickDummy \fIhttp://clickdummy\.net/\fR is a rapid mockup prototyping application for designers and dummies\.
.
.P
\fIhttp://clickdummy\.net\fR
.
.P
Node Knockout \fIhttp://nodeknockout\.com\fR organized the first ever node\-specific competition with hundreds of contestants\.
.
.P
\fIhttp://nodeknockout\.com\fR
.
.P
Widescript \fIhttp://widescript\.com\fR is an innovative app that helps you focus and interact with your texts \- on your desktop, your couch or on the go\.
.
.P
\fIhttp://widescript\.com\fR
.
.P
e\-resistable \fIhttp://www\.e\-resistible\.co\.uk/\fR is an online order takeaway system providing an intuitive way to fill your belly from your computer!
.
.P
\fIhttp://www\.e\-resistible\.co\.uk\fR
.
.P
Top Twitter Trends \fIhttp://toptwittertrends\.com\fR utilizes MongoDB, Socket\.IO, jQuery and many other exciting libraries to bring you trending tweets in realtime\.
.
.P
\fIhttp://toptwittertrends\.com\fR
.
.P
The applications shown above are not listed in any specific order\. To have an application added or removed please contact TJ Holowaychuk \fIhttp://github\.com/visionmedia\fR\.

252
docs/applications.html Normal file
View File

@@ -0,0 +1,252 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>
<div class='mp'>
<h2 id="Express">Express</h2>
<p class="man-name">
<code>applications</code>
</p>
<br />
<p><a href="http://learnboost.com">Learnboost</a> is a free online gradebook application, aimed to crush the competition with innovative, realtime, enjoyable features.</p>
<p><a href="http://learnboost.com"><img src="images/apps/learnboost.png" alt="LearnBoost" /></a></p>
<p><a href="http://storify.com">Storify</a> lets you turn what people post on social media websites into compelling stories.</p>
<p><a href="http://storify.com"><img src="images/apps/storify.png" alt="Storify" /></a></p>
<p><a href="http://pakistansurvey.org/">Pakistan Survey</a> by <a href="http://developmentseed.org">Development Seed</a>, provides in-depth agency-specific analysis from regional experts with data from 1,000 interviews across 120 villages in all seven tribal agencies and mapping of 142 reported drone strikes in FATA through July 2010.</p>
<p><a href="http://pakistansurvey.org"><img src="images/apps/developmentseed.png" alt="Pakistan Survey" /></a></p>
<p><a href="http://markup.io">Markup.IO</a> allows you to draw directly on <em>any</em> website, then share with others to share your thoughts.</p>
<p><a href="http://markup.io"><img src="images/apps/markupio.png" alt="Markup.IO" /></a></p>
<p><a href="http://scrabb.ly">Scrabb.ly</a> is a massively multiplayer scrabble game initially created for the <a href="http://nodeknockout.com/">Node Knockout</a> competition.</p>
<p><a href="http://scrabb.ly"><img src="images/apps/scrabbly.png" alt="Online Realtime Scrabble" /></a></p>
<p><a href="http://clickdummy.net/">ClickDummy</a> is a rapid mockup prototyping application for designers and dummies.</p>
<p><a href="http://clickdummy.net"><img src="images/apps/clickdummy.png" alt="Mockup Prototying" /></a></p>
<p><a href="http://nodeknockout.com">Node Knockout</a> organized the first ever node-specific competition with hundreds of contestants.</p>
<p><a href="http://nodeknockout.com"><img src="images/apps/nodeko.png" alt="Node Knockout Competition Express" /></a></p>
<p><a href="http://widescript.com">Widescript</a> is an innovative app that helps you focus and interact with your texts - on your desktop, your couch or on the go.</p>
<p><a href="http://widescript.com"><img src="images/apps/widescript.png" alt="Widescript" /></a></p>
<p><a href="http://www.e-resistible.co.uk/">e-resistable</a> is an online order takeaway system providing an intuitive way to fill your belly from your computer!</p>
<p><a href="http://www.e-resistible.co.uk"><img src="images/apps/e-resistable.png" alt="Online Takeaway" /></a></p>
<p><a href="http://toptwittertrends.com">Top Twitter Trends</a> utilizes MongoDB, Socket.IO, jQuery and many other exciting libraries to bring you trending tweets in realtime.</p>
<p><a href="http://toptwittertrends.com"><img src="images/apps/toptwittertrends.png" alt="Twitter Trends" /></a></p>
<br />
<p>The applications shown above are not listed in any specific order. To have an application added or removed please contact <a href="http://github.com/visionmedia">TJ Holowaychuk</a>.</p>
</div>
</div>
</div>
</body>
</html>

47
docs/applications.md Normal file
View File

@@ -0,0 +1,47 @@
<br />
[Learnboost](http://learnboost.com) is a free online gradebook application, aimed to crush the competition with innovative, realtime, enjoyable features.
[![LearnBoost](images/apps/learnboost.png)](http://learnboost.com)
[Storify](http://storify.com) lets you turn what people post on social media websites into compelling stories.
[![Storify](images/apps/storify.png)](http://storify.com)
[Pakistan Survey](http://pakistansurvey.org/) by [Development Seed](http://developmentseed.org), provides in-depth agency-specific analysis from regional experts with data from 1,000 interviews across 120 villages in all seven tribal agencies and mapping of 142 reported drone strikes in FATA through July 2010.
[![Pakistan Survey](images/apps/developmentseed.png)](http://pakistansurvey.org)
[Markup.IO](http://markup.io) allows you to draw directly on _any_ website, then share with others to share your thoughts.
[![Markup.IO](images/apps/markupio.png)](http://markup.io)
[Scrabb.ly](http://scrabb.ly) is a massively multiplayer scrabble game initially created for the [Node Knockout](http://nodeknockout.com/) competition.
[![Online Realtime Scrabble](images/apps/scrabbly.png)](http://scrabb.ly)
[ClickDummy](http://clickdummy.net/) is a rapid mockup prototyping application for designers and dummies.
[![Mockup Prototying](images/apps/clickdummy.png)](http://clickdummy.net)
[Node Knockout](http://nodeknockout.com) organized the first ever node-specific competition with hundreds of contestants.
[![Node Knockout Competition Express](images/apps/nodeko.png)](http://nodeknockout.com)
[Widescript](http://widescript.com) is an innovative app that helps you focus and interact with your texts - on your desktop, your couch or on the go.
[![Widescript](images/apps/widescript.png)](http://widescript.com)
[e-resistable](http://www.e-resistible.co.uk/) is an online order takeaway system providing an intuitive way to fill your belly from your computer!
[![Online Takeaway](images/apps/e-resistable.png)](http://www.e-resistible.co.uk)
[Top Twitter Trends](http://toptwittertrends.com) utilizes MongoDB, Socket.IO, jQuery and many other exciting libraries to bring you trending tweets in realtime.
[![Twitter Trends](images/apps/toptwittertrends.png)](http://toptwittertrends.com)
<br />
The applications shown above are not listed in any specific order. To have an application added or removed please contact [TJ Holowaychuk](http://github.com/visionmedia).

82
docs/contrib.1 Normal file
View File

@@ -0,0 +1,82 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "CONTRIB" "" "October 2010" "" ""
.
.SH "NAME"
\fBcontrib\fR
.
.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
.
.P
To check test coverage run:
.
.IP "" 4
.
.nf
$ make test\-cov
.
.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 \fI2\fR spaces\.
.
.IP "" 0
.
.SS "Documentation"
To contribute documentation edit the markdown files in \fI\./docs\fR, however do \fInot\fR run \fImake docs\fR, as they will be re\-built and published with each release\.

247
docs/contrib.html Normal file
View File

@@ -0,0 +1,247 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>
<div class='mp'>
<h2 id="Express">Express</h2>
<p class="man-name">
<code>contrib</code>
</p>
<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>
<p>To check test coverage run:</p>
<pre><code>$ make test-cov
</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>2</em> spaces.</li>
</ul>
<h3 id="Documentation">Documentation</h3>
<p>To contribute documentation edit the markdown files in <em>./docs</em>, however
do <em>not</em> run <em>make docs</em>, as they will be re-built and published with each release.</p>
</div>
</div>
</div>
</body>
</html>

38
docs/contrib.md Normal file
View File

@@ -0,0 +1,38 @@
### 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
To check test coverage run:
$ make test-cov
### 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 _2_ spaces.
### Documentation
To contribute documentation edit the markdown files in _./docs_, however
do _not_ run _make docs_, as they will be re-built and published with each release.

30
docs/executable.1 Normal file
View File

@@ -0,0 +1,30 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "EXECUTABLE" "" "October 2010" "" ""
.
.SH "NAME"
\fBexecutable\fR
.
.SH "Synopsis"
.
.nf
express [\-h|\-\-help] [\-v|\-\-version] [\-c|\-css ENGINE] [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
\-s, \-\-sessions Add session support
\-c, \-\-css ENGINE Add css ENGINE support (less|sass)\. Defaults to plain css
\-v, \-\-version Output framework version
\-h, \-\-help Display help information
.
.fi

221
docs/executable.html Normal file
View File

@@ -0,0 +1,221 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>
<div class='mp'>
<h2 id="Express">Express</h2>
<p class="man-name">
<code>executable</code>
</p>
<h2 id="Synopsis">Synopsis</h2>
<pre><code>express [-h|--help] [-v|--version] [-c|-css ENGINE] [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>-s, --sessions Add session support
-c, --css ENGINE Add css ENGINE support (less|sass). Defaults to plain css
-v, --version Output framework version
-h, --help Display help information
</code></pre>
</div>
</div>
</div>
</body>
</html>

18
docs/executable.md Normal file
View File

@@ -0,0 +1,18 @@
## Synopsis
express [-h|--help] [-v|--version] [-c|-css ENGINE] [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
-s, --sessions Add session support
-c, --css ENGINE Add css ENGINE support (less|sass). Defaults to plain css
-v, --version Output framework version
-h, --help Display help information

1871
docs/guide.1 Normal file

File diff suppressed because it is too large Load Diff

1419
docs/guide.html Normal file

File diff suppressed because it is too large Load Diff

1043
docs/guide.md Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
docs/images/apps/nodeko.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
docs/images/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
docs/images/bg.tile.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
docs/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
docs/images/top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

106
docs/index.1 Normal file
View File

@@ -0,0 +1,106 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "INDEX" "" "October 2010" "" ""
.
.SH "NAME"
\fBindex\fR
.
.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
Dynamic view helpers
.
.IP "\(bu" 4
Application level view options
.
.IP "\(bu" 4
Content negotiation
.
.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://github\.com/senchalabs/connect\fR
.
.IP "\(bu" 4
Executable \fIexecutable\.html\fR for generating applications quickly
.
.IP "\(bu" 4
High test coverage
.
.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 "\(bu" 4
Guillermo Rauch (guille \fIhttp://github\.com/guille\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 Connect \fIhttp://github\.com/senchalabs/connect\fR repo for middleware usage
.
.IP "\(bu" 4
View the Connect Wiki \fIhttp://wiki\.github\.com/senchalabs/connect/\fR for contrib middleware
.
.IP "\(bu" 4
View the examples \fIhttp://github\.com/visionmedia/express/tree/master/examples/\fR
.
.IP "\(bu" 4
View the source \fIhttp://github\.com/visionmedia/express\fR
.
.IP "" 0

254
docs/index.html Normal file
View File

@@ -0,0 +1,254 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>
<div class='mp'>
<h2 id="Express">Express</h2>
<p class="man-name">
<code>index</code>
</p>
<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>Dynamic view helpers</li>
<li>Application level view options</li>
<li>Content negotiation</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://github.com/senchalabs/connect">Connect</a></li>
<li><a href="executable.html">Executable</a> for generating applications quickly</li>
<li>High test coverage</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>
<li>Guillermo Rauch (<a href="http://github.com/guille">guille</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/senchalabs/connect">Connect</a> repo for middleware usage</li>
<li>View the <a href="http://wiki.github.com/senchalabs/connect/">Connect Wiki</a> for contrib middleware</li>
<li>View the <a href="http://github.com/visionmedia/express/tree/master/examples/">examples</a></li>
<li>View the <a href="http://github.com/visionmedia/express">source</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

42
docs/index.md Normal file
View File

@@ -0,0 +1,42 @@
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
## Features
* Robust routing
* Redirection helpers
* Dynamic view helpers
* Application level view options
* Content negotiation
* Focus on high performance
* View rendering and partials support
* Environment based configuration
* Session based flash notifications
* Built on [Connect](http://github.com/senchalabs/connect)
* [Executable](executable.html) for generating applications quickly
* High test coverage
## 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))
* Guillermo Rauch ([guille](http://github.com/guille))
## 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 [Connect](http://github.com/senchalabs/connect) repo for middleware usage
* View the [Connect Wiki](http://wiki.github.com/senchalabs/connect/) for contrib middleware
* View the [examples](http://github.com/visionmedia/express/tree/master/examples/)
* View the [source](http://github.com/visionmedia/express)

4
docs/layout/foot.html Normal file
View File

@@ -0,0 +1,4 @@
</div>
</div>
</body>
</html>

192
docs/layout/head.html Normal file
View File

@@ -0,0 +1,192 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>

347
docs/migrate.1 Normal file
View File

@@ -0,0 +1,347 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "MIGRATE" "" "October 2010" "" ""
.
.SH "NAME"
\fBmigrate\fR
.
.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 app = express\.createServer(
express\.logger(),
express\.methodOverride(),
express\.cookieDecoder()
);
.
.fi
.
.IP "" 0
.
.P
or:
.
.IP "" 4
.
.nf
var app = express\.createServer();
app\.use(express\.logger());
app\.use(express\.methodOverride());
app\.use(express\.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, res){
req\.param(\'id\');
});
.
.fi
.
.IP "" 0
.
.P
Route parameters are available via \fBreq\.params\fR:
.
.IP "" 4
.
.nf
app\.get(\'/user/:id\', function(req, res){
req\.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 third 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, 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

412
docs/migrate.html Normal file
View File

@@ -0,0 +1,412 @@
<html>
<head>
<title>Express - node web framework</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style>
#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-font-smoothing: antialiased;
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, h4 {
margin: 45px 0 0 0;
color: white;
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
h3 {
font-size: 18px; }
h4 {
margin-left: 10px;
font-size: 14px;
}
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; }
ul li ul {
margin: 0;
padding-left: 12px;
}
.man-name, #Express { display:none; }
.sect {
margin-left: 40px; }
img {
margin-left: 20px;
margin-bottom: 15px;
}
#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: 80px;
width: 550px; }
#toc {
position: fixed;
top: 0;
left: 0;
margin: 0 0 0 15px;
padding: 15px;
height: 100%;
background: rgba(0,0,0,0.2);
overflow: auto;
border-right: 1px solid rgba(255,255,255,0.05);
}
#toc li {
padding: 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>
<script>
$(function(){
$('.section').hide();
$('.toggle, a.section-title').toggle(function(){
$(this).siblings('ul').fadeIn(300);
return false;
}, function(){
$(this).siblings('ul').fadeOut(300);
return false;
});
});
</script>
</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="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="applications.html">Applications</a></li>
</ul>
<div class='mp'>
<h2 id="Express">Express</h2>
<p class="man-name">
<code>migrate</code>
</p>
<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 app = express.createServer(
express.logger(),
express.methodOverride(),
express.cookieDecoder()
);
</code></pre>
<p>or:</p>
<pre><code>var app = express.createServer();
app.use(express.logger());
app.use(express.methodOverride());
app.use(express.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, res){
req.param('id');
});
</code></pre>
<p>Route parameters are available via <code>req.params</code>:</p>
<pre><code>app.get('/user/:id', function(req, res){
req.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 third 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, 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>

189
docs/migrate.md Normal file
View File

@@ -0,0 +1,189 @@
### 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 app = express.createServer(
express.logger(),
express.methodOverride(),
express.cookieDecoder()
);
or:
var app = express.createServer();
app.use(express.logger());
app.use(express.methodOverride());
app.use(express.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, res){
req.param('id');
});
Route parameters are available via `req.params`:
app.get('/user/:id', function(req, res){
req.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 third 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, 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

View File

@@ -1,29 +0,0 @@
# Express examples
This page contains list of examples using Express.
- [auth](./auth) - Authentication with login and password
- [content-negotiation](./content-negotiation) - HTTP content negotiation
- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions
- [cookies](./cookies) - Working with cookies
- [downloads](./downloads) - Transferring files to client
- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs)
- [error-pages](./error-pages) - Creating error pages
- [error](./error) - Working with error middleware
- [hello-world](./hello-world) - Simple request handler
- [markdown](./markdown) - Markdown as template engine
- [multi-router](./multi-router) - Working with multiple Express routers
- [mvc](./mvc) - MVC-style controllers
- [online](./online) - Tracking online user activity with `online` and `redis` packages
- [params](./params) - Working with route parameters
- [resource](./resource) - Multiple HTTP operations on the same resource
- [route-map](./route-map) - Organizing routes using a map
- [route-middleware](./route-middleware) - Working with route middleware
- [route-separation](./route-separation) - Organizing routes per each resource
- [search](./search) - Search API
- [session](./session) - User sessions
- [static-files](./static-files) - Serving static files
- [vhost](./vhost) - Working with virtual hosts
- [view-constructor](./view-constructor) - Rendering views dynamically
- [view-locals](./view-locals) - Saving data in request object between middleware calls
- [web-service](./web-service) - Simple API service

126
examples/auth/app.js Normal file
View File

@@ -0,0 +1,126 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('../../lib/express'),
crypto = require('crypto');
var app = express.createServer();
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.bodyDecoder());
app.use(express.cookieDecoder());
app.use(express.session());
// Message helper, ideally we would use req.flash()
// however this is more light-weight for an example
app.dynamicHelpers({
message: function(req){
var err = req.session.error,
msg = req.session.success;
delete req.session.error;
delete req.session.success;
if (err) return '<p class="msg error">' + err + '</p>';
if (msg) return '<p class="msg success">' + msg + '</p>';
}
});
// Generate a salt for the user to prevent rainbow table attacks
var users = {
tj: {
name: 'tj',
salt: 'randomly-generated-salt',
pass: md5('foobar' + 'randomly-generated-salt')
}
};
// Used to generate a hash of the plain-text password + salt
function md5(str) {
return crypto.createHash('md5').update(str).digest('hex');
}
// Authenticate using our plain-object database of doom!
function authenticate(name, pass, fn) {
var user = users[name];
// query the db for the given username
if (!user) return fn(new Error('cannot find user'));
// apply the same algorithm to the POSTed password, applying
// the md5 against the pass / salt, if there is a match we
// found the user
if (user.pass == md5(pass + user.salt)) return fn(null, user);
// Otherwise password is invalid
fn(new Error('invalid password'));
}
function restrict(req, res, next) {
if (req.session.user) {
next();
} else {
req.session.error = 'Access denied!';
res.redirect('/login');
}
}
function accessLogger(req, res, next) {
console.log('/restricted accessed by %s', req.session.user.name);
next();
}
app.get('/', function(req, res){
res.redirect('/login');
});
app.get('/restricted', restrict, accessLogger, function(req, res){
res.send('Wahoo! restricted area');
});
app.get('/logout', function(req, res){
// destroy the user's session to log them out
// will be re-created next request
req.session.destroy(function(){
res.redirect('home');
});
});
app.get('/login', function(req, res){
if (req.session.user) {
req.session.success = 'Authenticated as ' + req.session.user.name
+ ' click to <a href="/logout">logout</a>. '
+ ' You may now access <a href="/restricted">/restricted</a>.';
}
res.render('login');
});
app.post('/login', function(req, res){
authenticate(req.body.username, req.body.password, function(err, user){
if (user) {
// Regenerate session when signing in
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
res.redirect('back');
});
} else {
req.session.error = 'Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")';
res.redirect('back');
}
});
});
app.listen(3000);
console.log('Express started on port 3000');

View File

@@ -1,134 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../..');
var hash = require('pbkdf2-password')()
var path = require('node:path');
var session = require('express-session');
var app = module.exports = express();
// config
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// middleware
app.use(express.urlencoded())
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'shhhh, very secret'
}));
// Session-persisted message middleware
app.use(function(req, res, next){
var err = req.session.error;
var msg = req.session.success;
delete req.session.error;
delete req.session.success;
res.locals.message = '';
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
next();
});
// dummy database
var users = {
tj: { name: 'tj' }
};
// when you create a user, generate a salt
// and hash the password ('foobar' is the pass here)
hash({ password: 'foobar' }, function (err, pass, salt, hash) {
if (err) throw err;
// store the salt & hash in the "db"
users.tj.salt = salt;
users.tj.hash = hash;
});
// Authenticate using our plain-object database of doom!
function authenticate(name, pass, fn) {
if (!module.parent) console.log('authenticating %s:%s', name, pass);
var user = users[name];
// query the db for the given username
if (!user) return fn(null, null)
// apply the same algorithm to the POSTed password, applying
// the hash against the pass / salt, if there is a match we
// found the user
hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
if (err) return fn(err);
if (hash === user.hash) return fn(null, user)
fn(null, null)
});
}
function restrict(req, res, next) {
if (req.session.user) {
next();
} else {
req.session.error = 'Access denied!';
res.redirect('/login');
}
}
app.get('/', function(req, res){
res.redirect('/login');
});
app.get('/restricted', restrict, function(req, res){
res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
});
app.get('/logout', function(req, res){
// destroy the user's session to log them out
// will be re-created next request
req.session.destroy(function(){
res.redirect('/');
});
});
app.get('/login', function(req, res){
res.render('login');
});
app.post('/login', function (req, res, next) {
if (!req.body) return res.sendStatus(400)
authenticate(req.body.username, req.body.password, function(err, user){
if (err) return next(err)
if (user) {
// Regenerate session when signing in
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
req.session.success = 'Authenticated as ' + user.name
+ ' click to <a href="/logout">logout</a>. '
+ ' You may now access <a href="/restricted">/restricted</a>.';
res.redirect(req.get('Referrer') || '/');
});
} else {
req.session.error = 'Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")';
res.redirect('/login');
}
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -1,16 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><%= title %></title>
<title>Authentication Example</title>
<style>
body {
padding: 50px;
font: 13px Helvetica, Arial, sans-serif;
}
.error {
color: red;
color: red
}
.success {
color: green;
@@ -18,3 +16,6 @@
</style>
</head>
<body>
<%- body %>
</body>
</html>

View File

@@ -1,21 +1,16 @@
<%- include('head', { title: 'Authentication Example' }) -%>
<h1>Login</h1>
<%- message %>
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
Try accessing <a href="/restricted">/restricted</a>.
<form method="post" action="/login">
<p>
<label for="username">Username:</label>
<input type="text" name="username" id="username">
<label>Username:</label>
<input type="text" name="username">
</p>
<p>
<label for="password">Password:</label>
<input type="text" name="password" id="password">
<label>Password:</label>
<input type="text" name="password">
</p>
<p>
<input type="submit" value="Login">
</p>
</form>
<%- include('foot') -%>
</form>

25
examples/blog/app.js Normal file
View File

@@ -0,0 +1,25 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('./../../lib/express');
// Our app IS the exports, this prevents require('./app').app,
// instead it is require('./app');
var app = module.exports = express.createServer();
// Illustrates that an app can be broken into
// several files, but yet extend the same app
require('./main');
require('./contact');
// Illustrates that one app (Server instance) can
// be "mounted" to another at the given route.
app.use('/blog', require('./blog'));
app.listen(3000);
console.log('Express started on port 3000');

View File

@@ -0,0 +1,45 @@
/**
* Module dependencies.
*/
var express = require('./../../../lib/express'),
fs = require('fs');
// Export our app as the module
var app = module.exports = express.createServer();
// Set views directory
app.set('views', __dirname + '/views');
// Load our posts
var posts = JSON.parse(fs.readFileSync(__dirname + '/posts.json', 'utf8'));
// Set our default view engine to "ejs"
app.set('view engine', 'ejs');
app.dynamicHelpers({
basepath: function(){
// "this" is the app, we can
// dynamically provide the "home"
// setting to all views
return this.set('home');
}
});
app.get('/', function(req, res){
res.render('index', {
locals: {
posts: posts
}
});
});
app.get('/post/:id', function(req, res){
var id = req.params.id;
res.render('post', {
locals: {
post: posts[id]
}
});
});

View File

@@ -0,0 +1,4 @@
[
{ "id": 0, "title": "Post one", "body": "Just some lame post" },
{ "id": 1, "title": "Post two", "body": "Just another lame post" }
]

View File

@@ -0,0 +1,2 @@
<h2>Posts</h2>
<%- partial('post', { collection: posts, as: global }) %>

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Blog Example</title>
</head>
<body>
<h1>Best Blog Ever</h1>
<%- body %>
</body>
</html>

View File

@@ -0,0 +1,2 @@
<h3><a href="<%= basepath %>/post/<%= id %>"><%= title %></a></h3>
<p><%= body %></p>

View File

@@ -0,0 +1 @@
<%- partial('post', { object: post, as: global }) %>

9
examples/blog/contact.js Normal file
View File

@@ -0,0 +1,9 @@
// in ./app.js we did "module.exports", allowing
// us to grab the app from the parent module (the one
// which required it)
var app = module.parent.exports;
app.get('/contact', function(req, res){
res.send('<p>Wahoo contact page</p>');
});

10
examples/blog/main.js Normal file
View File

@@ -0,0 +1,10 @@
// in ./app.js we did "module.exports", allowing
// us to grab the app from the parent module (the one
// which required it)
var app = module.parent.exports;
app.get('/', function(req, res){
res.send('<p>Visit <a href="/blog">/blog</a>'
+ ' or <a href="/contact">/contact</a></p>');
});

View File

@@ -1,9 +0,0 @@
'use strict'
var users = [];
users.push({ name: 'Tobi' });
users.push({ name: 'Loki' });
users.push({ name: 'Jane' });
module.exports = users;

View File

@@ -1,46 +0,0 @@
'use strict'
var express = require('../../');
var app = module.exports = express();
var users = require('./db');
// so either you can deal with different types of formatting
// for expected response in index.js
app.get('/', function(req, res){
res.format({
html: function(){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('') + '</ul>');
},
text: function(){
res.send(users.map(function(user){
return ' - ' + user.name + '\n';
}).join(''));
},
json: function(){
res.json(users);
}
});
});
// or you could write a tiny middleware like
// this to add a layer of abstraction
// and make things a bit more declarative:
function format(path) {
var obj = require(path);
return function(req, res){
res.format(obj);
};
}
app.get('/users', format('./users'));
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,19 +0,0 @@
'use strict'
var users = require('./db');
exports.html = function(req, res){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('') + '</ul>');
};
exports.text = function(req, res){
res.send(users.map(function(user){
return ' - ' + user.name + '\n';
}).join(''));
};
exports.json = function(req, res){
res.json(users);
};

View File

@@ -1,25 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var cookieSession = require('cookie-session');
var express = require('../../');
var app = module.exports = express();
// add req.session cookie support
app.use(cookieSession({ secret: 'manny is cool' }));
// do something with the session
app.get('/', function (req, res) {
req.session.count = (req.session.count || 0) + 1
res.send('viewed ' + req.session.count + ' times\n')
})
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

46
examples/cookies/app.js Normal file
View File

@@ -0,0 +1,46 @@
/**
* Module dependencies.
*/
var express = require('./../../lib/express');
var app = express.createServer(
// Place default Connect favicon above logger so it is not in
// the logging output
express.favicon(),
// Custom logger format
express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b[0m :response-time' }),
// Provides req.cookies
express.cookieDecoder(),
// Parses x-www-form-urlencoded request bodies (and json)
express.bodyDecoder()
);
app.get('/', function(req, res){
if (req.cookies.remember) {
res.send('Remembered :). Click to <a href="/forget">forget</a>!.');
} else {
res.send('<form method="post"><p>Check to <label>'
+ '<input type="checkbox" name="remember"/> remember me</label> '
+ '<input type="submit" value="Submit"/>.</p></form>');
}
});
app.get('/forget', function(req, res){
res.clearCookie('remember');
res.redirect('back');
});
app.post('/', function(req, res){
if (req.body.remember) {
res.cookie('remember', '1', { path: '/', expires: new Date(Date.now() + 900000), httpOnly: true });
}
res.redirect('back');
});
app.listen(3000);
console.log('Express started on port 3000');

View File

@@ -1,53 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var app = module.exports = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
// custom log format
if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used
// for signing the cookies.
app.use(cookieParser('my secret here'));
// parses x-www-form-urlencoded
app.use(express.urlencoded())
app.get('/', function(req, res){
if (req.cookies.remember) {
res.send('Remembered :). Click to <a href="/forget">forget</a>!.');
} else {
res.send('<form method="post"><p>Check to <label>'
+ '<input type="checkbox" name="remember"/> remember me</label> '
+ '<input type="submit" value="Submit"/>.</p></form>');
}
});
app.get('/forget', function(req, res){
res.clearCookie('remember');
res.redirect(req.get('Referrer') || '/');
});
app.post('/', function(req, res){
var minute = 60000;
if (req.body && req.body.remember) {
res.cookie('remember', 1, { maxAge: minute })
}
res.redirect(req.get('Referrer') || '/');
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

32
examples/downloads/app.js Normal file
View File

@@ -0,0 +1,32 @@
/**
* Module dependencies.
*/
var express = require('./../../lib/express');
var app = express.createServer();
app.get('/', function(req, res){
res.send('<ul>'
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
+ '</ul>');
});
app.get('/files/*', function(req, res){
var file = req.params[0];
res.download(__dirname + '/files/' + file);
});
app.error(function(err, req, res, next){
if (process.ENOENT == err.errno) {
res.send('Cant find that file, sorry!');
} else {
// Not a 404
next(err);
}
});
app.listen(3000);
console.log('Express started on port 3000');

View File

@@ -1,2 +0,0 @@
Only for test.
The file name is faked.

View File

@@ -1 +1 @@
what an amazing download
wow supes cool are you glad you downloaded this?

View File

@@ -1,3 +0,0 @@
* milk
* eggs
* bread

View File

@@ -1,40 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
// path to where the files are stored on disk
var FILES_DIR = path.join(__dirname, 'files')
app.get('/', function(req, res){
res.send('<ul>' +
'<li>Download <a href="/files/notes/groceries.txt">notes/groceries.txt</a>.</li>' +
'<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>' +
'<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>' +
'<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>' +
'</ul>')
});
// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/*file', function (req, res, next) {
res.download(req.params.file.join('/'), { root: FILES_DIR }, function (err) {
if (!err) return; // file sent
if (err.status !== 404) return next(err); // non-404 error
// file for download not found
res.statusCode = 404;
res.send('Cant find that file, sorry!');
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

32
examples/ejs/app.js Normal file
View File

@@ -0,0 +1,32 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* 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);

View File

@@ -1,57 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
// Register ejs as .html. If we did
// not call this, we would need to
// name our views foo.ejs instead
// of foo.html. The __express method
// is simply a function that engines
// use to hook into the Express view
// system by default, so if we want
// to change "foo.ejs" to "foo.html"
// we simply pass _any_ function, in this
// case `ejs.__express`.
app.engine('.html', require('ejs').__express);
// Optional since express defaults to CWD/views
app.set('views', path.join(__dirname, 'views'));
// Path to our public directory
app.use(express.static(path.join(__dirname, 'public')));
// Without this you would need to
// supply the extension to res.render()
// ex: res.render('users.html').
app.set('view engine', 'html');
// Dummy users
var users = [
{ name: 'tobi', email: 'tobi@learnboost.com' },
{ name: 'loki', email: 'loki@learnboost.com' },
{ name: 'jane', email: 'jane@learnboost.com' }
];
app.get('/', function(req, res){
res.render('users', {
users: users,
title: "EJS example",
header: "Some users"
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,4 +0,0 @@
body {
padding: 50px 80px;
font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif;
}

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -1,9 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><%= title %></title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>

View File

@@ -0,0 +1,6 @@
<html>
<body>
<h1>Users</h1>
<%- body %>
</body>
</html>

View File

@@ -0,0 +1 @@
<li><%= user.name %> &lt;<%= user.email %>&gt;</li>

View File

@@ -0,0 +1,3 @@
<ul id="users">
<%- partial('user', users) %>
</ul>

View File

@@ -1,10 +0,0 @@
<%- include('header.html') -%>
<h1>Users</h1>
<ul id="users">
<% users.forEach(function(user){ %>
<li><%= user.name %> &lt;<%= user.email %>&gt;</li>
<% }) %>
</ul>
<%- include('footer.html') -%>

103
examples/error-pages/app.js Normal file
View File

@@ -0,0 +1,103 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('./../../lib/express');
var app = express.createServer(),
sys = require('sys');
// Serve default connect favicon
app.use(express.favicon());
// Logger is placed below favicon, so favicon.ico
// requests will not be logged
app.use(express.logger({ format: '":method :url" :status' }));
// "app.router" positions our routes
// specifically above the middleware
// assigned below
app.use(app.router);
// When no more middleware require execution, aka
// our router is finished and did not respond, we
// can assume that it is "not found". Instead of
// letting Connect deal with this, we define our
// custom middleware here to simply pass a NotFound
// exception
app.use(function(req, res, next){
next(new NotFound(req.url));
});
app.set('views', __dirname + '/views');
// Provide our app with the notion of NotFound exceptions
function NotFound(path){
this.name = 'NotFound';
if (path) {
Error.call(this, 'Cannot find ' + path);
this.path = path;
} else {
Error.call(this, 'Not Found');
}
Error.captureStackTrace(this, arguments.callee);
}
sys.inherits(NotFound, Error);
// 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.
// These handlers could potentially be defined within
// configure() blocks to provide introspection when
// in the development environment.
app.error(function(err, req, res, next){
if (err instanceof NotFound) {
res.render('404.jade', {
status: 404,
locals: {
error: err
}
});
} 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', {
status: 500,
locals: {
error: err
}
});
});
// Routes
app.get('/', function(req, res){
res.render('index.jade');
});
app.get('/404', function(req, res){
throw new NotFound;
});
app.get('/500', function(req, res, next){
next(new Error('keyboard cat!'));
});
app.listen(3000);
console.log('Express app started on port 3000');

View File

@@ -1,103 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
var logger = require('morgan');
var silent = process.env.NODE_ENV === 'test'
// general config
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// our custom "verbose errors" setting
// which we can use in the templates
// via settings['verbose errors']
app.enable('verbose errors');
// disable them in production
// use $ NODE_ENV=production node examples/error-pages
if (app.settings.env === 'production') app.disable('verbose errors')
silent || app.use(logger('dev'));
// Routes
app.get('/', function(req, res){
res.render('index.ejs');
});
app.get('/404', function(req, res, next){
// trigger a 404 since no other middleware
// will match /404 after this one, and we're not
// responding here
next();
});
app.get('/403', function(req, res, next){
// trigger a 403 error
var err = new Error('not allowed!');
err.status = 403;
next(err);
});
app.get('/500', function(req, res, next){
// trigger a generic (500) error
next(new Error('keyboard cat!'));
});
// Error handlers
// Since this is the last non-error-handling
// middleware use()d, we assume 404, as nothing else
// responded.
// $ curl http://localhost:3000/notfound
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
app.use(function(req, res, next){
res.status(404);
res.format({
html: function () {
res.render('404', { url: req.url })
},
json: function () {
res.json({ error: 'Not found' })
},
default: function () {
res.type('txt').send('Not found')
}
})
});
// error-handling middleware, take the same form
// as regular middleware, however they require an
// arity of 4, aka the signature (err, req, res, next).
// when connect has an error, it will invoke ONLY error-handling
// middleware.
// If we were to next() here any remaining non-error-handling
// middleware would then be executed, or if we next(err) to
// continue passing the error, only error-handling middleware
// would remain being executed, however here
// we simply respond with an error page.
app.use(function(err, req, res, next){
// we may use properties of the error object
// here and next(err) appropriately, or if
// we possibly recovered from the error, simply next().
res.status(err.status || 500);
res.render('500', { error: err });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,3 +0,0 @@
<%- include('error_header') -%>
<h2>Cannot find <%= url %></h2>
<%- include('footer') -%>

View File

@@ -0,0 +1,4 @@
- if (error.path)
h2 Cannot find #{error.path}
- else
h2 Page Not Found

View File

@@ -1,8 +0,0 @@
<%- include('error_header') -%>
<h2>Error: <%= error.message %></h2>
<% if (settings['verbose errors']) { %>
<pre><%= error.stack %></pre>
<% } else { %>
<p>An error occurred!</p>
<% } %>
<%- include('footer') -%>

View File

@@ -0,0 +1,2 @@
h1 Error: #{error.message}
pre= error.stack

View File

@@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Error</title>
</head>
<body>
<h1>An error occurred!</h1>

Some files were not shown because too many files have changed in this diff Show More