Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75361fb177 | ||
|
|
21f9b386db | ||
|
|
271cb16ecd | ||
|
|
803ec213d7 | ||
|
|
9e9042f1eb | ||
|
|
ec4c86f46d | ||
|
|
45f22ec602 | ||
|
|
0e1eb72058 | ||
|
|
4690b6cdf2 | ||
|
|
22204a5ce1 | ||
|
|
1ec16c0450 |
@@ -1,11 +0,0 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.js,*.json,*.yml}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
@@ -1,2 +0,0 @@
|
||||
coverage
|
||||
node_modules
|
||||
@@ -1,10 +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 }]
|
||||
117
.github/workflows/ci.yml
vendored
@@ -1,117 +0,0 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- '4.x'
|
||||
- '5.x'
|
||||
- '5.0'
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
# 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@v4
|
||||
- name: Setup Node.js {{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --ignore-scripts --only=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]
|
||||
# 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@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
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
|
||||
cp coverage/lcov.info "coverage/${{ matrix.node-version }}.lcov"
|
||||
|
||||
- name: Collect code coverage
|
||||
run: |
|
||||
mv ./coverage "./${{ matrix.node-version }}"
|
||||
mkdir ./coverage
|
||||
mv "./${{ matrix.node-version }}" "./coverage/${{ matrix.node-version }}"
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
retention-days: 1
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install lcov
|
||||
shell: bash
|
||||
run: sudo apt-get -y install lcov
|
||||
|
||||
- name: Collect coverage reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
|
||||
- name: Merge coverage reports
|
||||
shell: bash
|
||||
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./coverage/lcov.info
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
66
.github/workflows/codeql.yml
vendored
@@ -1,66 +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"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
|
||||
with:
|
||||
languages: javascript
|
||||
# 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@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
|
||||
with:
|
||||
category: "/language:javascript"
|
||||
100
.github/workflows/legacy.yml
vendored
@@ -1,100 +0,0 @@
|
||||
name: legacy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- '4.x'
|
||||
- '5.x'
|
||||
- '5.0'
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
# 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@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
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
|
||||
cp coverage/lcov.info "coverage/${{ matrix.node-version }}.lcov"
|
||||
|
||||
- name: Collect code coverage
|
||||
run: |
|
||||
mv ./coverage "./${{ matrix.node-version }}"
|
||||
mkdir ./coverage
|
||||
mv "./${{ matrix.node-version }}" "./coverage/${{ matrix.node-version }}"
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
retention-days: 1
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install lcov
|
||||
shell: bash
|
||||
run: sudo apt-get -y install lcov
|
||||
|
||||
- name: Collect coverage reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
|
||||
- name: Merge coverage reports
|
||||
shell: bash
|
||||
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./coverage/lcov.info
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
25
.gitignore
vendored
@@ -1,16 +1,13 @@
|
||||
# npm
|
||||
node_modules
|
||||
package-lock.json
|
||||
npm-shrinkwrap.json
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.gz
|
||||
|
||||
# Coveralls
|
||||
.nyc_output
|
||||
coverage
|
||||
|
||||
# Benchmarking
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.swp
|
||||
*.swo
|
||||
benchmarks/graphs
|
||||
|
||||
# ignore additional files using core.excludesFile
|
||||
# https://git-scm.com/docs/gitignore
|
||||
testing.js
|
||||
node_modules/
|
||||
|
||||
0
test/fixtures/broken.send → .gitmodules
vendored
7
.npmignore
Normal file
@@ -0,0 +1,7 @@
|
||||
.git*
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
92
Charter.md
@@ -1,92 +0,0 @@
|
||||
# Express Charter
|
||||
|
||||
## Section 0: Guiding Principles
|
||||
|
||||
The Express project is part of the OpenJS Foundation which operates
|
||||
transparently, openly, collaboratively, and ethically.
|
||||
Project proposals, timelines, and status must not merely be open, but
|
||||
also easily visible to outsiders.
|
||||
|
||||
## Section 1: Scope
|
||||
|
||||
Express is a HTTP web server framework with a simple and expressive API
|
||||
which is highly aligned with Node.js core. We aim to be the best in
|
||||
class for writing performant, spec compliant, and powerful web servers
|
||||
in Node.js. As one of the oldest and most popular web frameworks in
|
||||
the ecosystem, we have an important place for new users and experts
|
||||
alike.
|
||||
|
||||
### 1.1: In-scope
|
||||
|
||||
Express is made of many modules spread between three GitHub Orgs:
|
||||
|
||||
- [expressjs](http://github.com/expressjs/): Top level middleware and
|
||||
libraries
|
||||
- [pillarjs](http://github.com/pillarjs/): Components which make up
|
||||
Express but can also be used for other web frameworks
|
||||
- [jshttp](http://github.com/jshttp/): Low level HTTP libraries
|
||||
|
||||
### 1.2: Out-of-Scope
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 2: Relationship with OpenJS Foundation CPC.
|
||||
|
||||
Technical leadership for the projects within the OpenJS Foundation is
|
||||
delegated to the projects through their project charters by the OpenJS
|
||||
Cross Project Council (CPC). In the case of the Express project, it is
|
||||
delegated to the Express Technical Committee ("TC").
|
||||
|
||||
This Technical Committee is in charge of both the day-to-day operations
|
||||
of the project, as well as its technical management. This charter can
|
||||
be amended by the TC requiring at least two approvals and a minimum two
|
||||
week comment period for other TC members or CPC members to object. Any
|
||||
changes the CPC wishes to propose will be considered a priority but
|
||||
will follow the same process.
|
||||
|
||||
### 2.1 Other Formal Project Relationships
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 3: Express Governing Body
|
||||
|
||||
The Express project is managed by the Technical Committee ("TC").
|
||||
Members can be added to the TC at any time. Any committer can nominate
|
||||
another committer to the TC and the TC uses its standard consensus
|
||||
seeking process to evaluate whether or not to add this new member.
|
||||
Members who do not participate consistently at the level of a majority
|
||||
of the other members are expected to resign.
|
||||
|
||||
## Section 4: Roles & Responsibilities
|
||||
|
||||
The Express TC manages all aspects of both the technical and community
|
||||
parts of the project. Members of the TC should attend the regular
|
||||
meetings when possible, and be available for discussion of time
|
||||
sensitive or important issues.
|
||||
|
||||
### Section 4.1 Project Operations & Management
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
### Section 4.2: Decision-making, Voting, and/or Elections
|
||||
|
||||
The Express TC uses a "consensus seeking" process for issues that are
|
||||
escalated to the TC. The group tries to find a resolution that has no
|
||||
open objections among TC members. If a consensus cannot be reached
|
||||
that has no objections then a majority wins vote is called. It is also
|
||||
expected that the majority of decisions made by the TC are via a
|
||||
consensus seeking process and that voting is only used as a last-resort.
|
||||
|
||||
Resolution may involve returning the issue to committers with
|
||||
suggestions on how to move forward towards a consensus. It is not
|
||||
expected that a meeting of the TC will resolve all issues on its
|
||||
agenda during that meeting and may prefer to continue the discussion
|
||||
happening among the committers.
|
||||
|
||||
### Section 4.3: Other Project Roles
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 5: Definitions
|
||||
|
||||
Section Intentionally Left Blank
|
||||
@@ -1,139 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
As a member of the Open JS Foundation, Express has adopted the
|
||||
[Contributor Covenant 2.0][cc-20-doc].
|
||||
|
||||
If an issue arises and you cannot resolve it directly with the parties
|
||||
involved, you can report it to the Express project TC through the following
|
||||
email: express-coc@lists.openjsf.org
|
||||
|
||||
In addition, the OpenJS Foundation maintains a Code of Conduct Panel (CoCP).
|
||||
This is a foundation-wide team established to manage escalation when a reporter
|
||||
believes that a report to a member project or the CPC has not been properly
|
||||
handled. In order to escalate to the CoCP send an email to
|
||||
coc-escalation@lists.openjsf.org.
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances
|
||||
of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for
|
||||
moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail
|
||||
address, posting via an official social media account, or acting as an
|
||||
appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
express-coc@lists.openjsf.org. All complaints will be reviewed and
|
||||
investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited
|
||||
interaction with those enforcing the Code of Conduct, is allowed during this
|
||||
period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
project community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant, version 2.0][cc-20-doc].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[cc-20-doc]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,51 +0,0 @@
|
||||
# Express Collaborator Guide
|
||||
|
||||
## Website Issues
|
||||
|
||||
Open issues for the expressjs.com website in https://github.com/expressjs/expressjs.com.
|
||||
|
||||
## PRs and Code contributions
|
||||
|
||||
* Tests must pass.
|
||||
* Follow the [JavaScript Standard Style](http://standardjs.com/) and `npm run lint`.
|
||||
* If you fix a bug, add a test.
|
||||
|
||||
## Branches
|
||||
|
||||
Use the `master` branch for bug fixes or minor work that is intended for the
|
||||
current release stream.
|
||||
|
||||
Use the correspondingly named branch, e.g. `5.0`, for anything intended for
|
||||
a future release of Express.
|
||||
|
||||
## Steps for contributing
|
||||
|
||||
1. [Create an issue](https://github.com/expressjs/express/issues/new) for the
|
||||
bug you want to fix or the feature that you want to add.
|
||||
2. Create your own [fork](https://github.com/expressjs/express) on GitHub, then
|
||||
checkout your fork.
|
||||
3. Write your code in your local copy. It's good practice to create a branch for
|
||||
each new issue you work on, although not compulsory.
|
||||
4. To run the test suite, first install the dependencies by running `npm install`,
|
||||
then run `npm test`.
|
||||
5. Ensure your code is linted by running `npm run lint` -- fix any issue you
|
||||
see listed.
|
||||
6. If the tests pass, you can commit your changes to your fork and then create
|
||||
a pull request from there. Make sure to reference your issue from the pull
|
||||
request comments by including the issue number e.g. `#123`.
|
||||
|
||||
## Issues which are questions
|
||||
|
||||
We will typically close any vague issues or questions that are specific to some
|
||||
app you are writing. Please double check the docs and other references before
|
||||
being trigger happy with posting a question issue.
|
||||
|
||||
Things that will help get your question issue looked at:
|
||||
|
||||
* Full and runnable JS code.
|
||||
* Clear description of the problem or unexpected behavior.
|
||||
* Clear description of the expected result.
|
||||
* Steps you have taken to debug it yourself.
|
||||
|
||||
If you post a question and do not outline the above items or make it easy for
|
||||
us to understand and reproduce your issue, it will be closed.
|
||||
209
Contributing.md
@@ -1,209 +0,0 @@
|
||||
# Express.js Community Contributing Guide 1.0
|
||||
|
||||
The goal of this document is to create a contribution process that:
|
||||
|
||||
* Encourages new contributions.
|
||||
* Encourages contributors to remain involved.
|
||||
* Avoids unnecessary processes and bureaucracy whenever possible.
|
||||
* Creates a transparent decision making process that makes it clear how
|
||||
contributors can be involved in decision making.
|
||||
|
||||
## Vocabulary
|
||||
|
||||
* A **Contributor** is any individual creating or commenting on an issue or pull request.
|
||||
* A **Committer** is a subset of contributors who have been given write access to the repository.
|
||||
* A **Project Captain** is the lead maintainer of a repository.
|
||||
* A **TC (Technical Committee)** is a group of committers representing the required technical
|
||||
expertise to resolve rare disputes.
|
||||
* A **Triager** is a subset of contributors who have been given triage access to the repository.
|
||||
|
||||
## Logging Issues
|
||||
|
||||
Log an issue for any question or problem you might have. When in doubt, log an issue, and
|
||||
any additional policies about what to include will be provided in the responses. The only
|
||||
exception is security disclosures which should be sent privately.
|
||||
|
||||
Committers may direct you to another repository, ask for additional clarifications, and
|
||||
add appropriate metadata before the issue is addressed.
|
||||
|
||||
Please be courteous and respectful. Every participant is expected to follow the
|
||||
project's Code of Conduct.
|
||||
|
||||
## Contributions
|
||||
|
||||
Any change to resources in this repository must be through pull requests. This applies to all changes
|
||||
to documentation, code, binary files, etc. Even long term committers and TC members must use
|
||||
pull requests.
|
||||
|
||||
No pull request can be merged without being reviewed.
|
||||
|
||||
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
|
||||
contributors in other timezones have time to review. Consideration should also be given to
|
||||
weekends and other holiday periods to ensure active committers all have reasonable time to
|
||||
become involved in the discussion and review process if they wish.
|
||||
|
||||
The default for each contribution is that it is accepted once no committer has an objection.
|
||||
During a review, committers may also request that a specific contributor who is most versed in a
|
||||
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
|
||||
process for contributions to land. Once all issues brought by committers are addressed it can
|
||||
be landed by any committer.
|
||||
|
||||
In the case of an objection being raised in a pull request by another committer, all involved
|
||||
committers should seek to arrive at a consensus by way of addressing concerns being expressed
|
||||
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
|
||||
|
||||
If a contribution is controversial and committers cannot agree about how to get it to land
|
||||
or if it should land then it should be escalated to the TC. TC members should regularly
|
||||
discuss pending contributions in order to find a resolution. It is expected that only a
|
||||
small minority of issues be brought to the TC for resolution and that discussion and
|
||||
compromise among committers be the default resolution mechanism.
|
||||
|
||||
## Becoming a Triager
|
||||
|
||||
Anyone can become a triager! Read more about the process of being a triager in
|
||||
[the triage process document](Triager-Guide.md).
|
||||
|
||||
Currently, any existing [organization member](https://github.com/orgs/expressjs/people) can nominate
|
||||
a new triager. If you are interested in becoming a triager, our best advice is to actively participate
|
||||
in the community by helping triaging issues and pull requests. As well we recommend
|
||||
to engage in other community activities like attending the TC meetings, and participating in the Slack
|
||||
discussions.
|
||||
|
||||
You can also reach out to any of the [organization members](https://github.com/orgs/expressjs/people)
|
||||
if you have questions or need guidance.
|
||||
|
||||
## Becoming a Committer
|
||||
|
||||
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
|
||||
and added as a committer, and be given write access to the repository.
|
||||
|
||||
Committers are expected to follow this policy and continue to send pull requests, go through
|
||||
proper review, and have other committers merge their pull requests.
|
||||
|
||||
## TC Process
|
||||
|
||||
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
|
||||
The group tries to find a resolution that has no open objections among TC members.
|
||||
If a consensus cannot be reached that has no objections then a majority wins vote
|
||||
is called. It is also expected that the majority of decisions made by the TC are via
|
||||
a consensus seeking process and that voting is only used as a last-resort.
|
||||
|
||||
Resolution may involve returning the issue to project captains with suggestions on
|
||||
how to move forward towards a consensus. It is not expected that a meeting of the TC
|
||||
will resolve all issues on its agenda during that meeting and may prefer to continue
|
||||
the discussion happening among the project captains.
|
||||
|
||||
Members can be added to the TC at any time. Any TC member can nominate another committer
|
||||
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
|
||||
not to add this new member. The TC will consist of a minimum of 3 active members and a
|
||||
maximum of 10. If the TC should drop below 5 members the active TC members should nominate
|
||||
someone new. If a TC member is stepping down, they are encouraged (but not required) to
|
||||
nominate someone to take their place.
|
||||
|
||||
TC members will be added as admin's on the Github orgs, npm orgs, and other resources as
|
||||
necessary to be effective in the role.
|
||||
|
||||
To remain "active" a TC member should have participation within the last 12 months and miss
|
||||
no more than six consecutive TC meetings. Our goal is to increase participation, not punish
|
||||
people for any lack of participation, this guideline should be only be used as such
|
||||
(replace an inactive member with a new active one, for example). Members who do not meet this
|
||||
are expected to step down. If A TC member does not step down, an issue can be opened in the
|
||||
discussions repo to move them to inactive status. TC members who step down or are removed due
|
||||
to inactivity will be moved into inactive status.
|
||||
|
||||
Inactive status members can become active members by self nomination if the TC is not already
|
||||
larger than the maximum of 10. They will also be given preference if, while at max size, an
|
||||
active member steps down.
|
||||
|
||||
## Project Captains
|
||||
|
||||
The Express TC can designate captains for individual projects/repos in the
|
||||
organizations. These captains are responsible for being the primary
|
||||
day-to-day maintainers of the repo on a technical and community front.
|
||||
Repo captains are empowered with repo ownership and package publication rights.
|
||||
When there are conflicts, especially on topics that effect the Express project
|
||||
at large, captains are responsible to raise it up to the TC and drive
|
||||
those conflicts to resolution. Captains are also responsible for making sure
|
||||
community members follow the community guidelines, maintaining the repo
|
||||
and the published package, as well as in providing user support.
|
||||
|
||||
Like TC members, Repo captains are a subset of committers.
|
||||
|
||||
To become a captain for a project the candidate is expected to participate in that
|
||||
project for at least 6 months as a committer prior to the request. They should have
|
||||
helped with code contributions as well as triaging issues. They are also required to
|
||||
have 2FA enabled on both their GitHub and npm accounts. Any TC member or existing
|
||||
captain on the repo can nominate another committer to the captain role, submit a PR to
|
||||
this doc, under `Current Project Captains` section (maintaining the sort order) with
|
||||
the project, their GitHub handle and npm username (if different). The PR will require
|
||||
at least 2 approvals from TC members and 2 weeks hold time to allow for comment and/or
|
||||
dissent. When the PR is merged, a TC member will add them to the proper GitHub/npm groups.
|
||||
|
||||
### Active Projects and Captains
|
||||
|
||||
- `expressjs/badgeboard`: @wesleytodd
|
||||
- `expressjs/basic-auth-connect`: N/A
|
||||
- `expressjs/body-parser`: @wesleytodd, @jonchurch
|
||||
- `expressjs/compression`: N/A
|
||||
- `expressjs/connect-multiparty`: N/A
|
||||
- `expressjs/cookie-parser`: @wesleytodd, @UlisesGascon
|
||||
- `expressjs/cookie-session`: N/A
|
||||
- `expressjs/cors`: @jonchurch
|
||||
- `expressjs/discussions`: @wesleytodd
|
||||
- `expressjs/errorhandler`: N/A
|
||||
- `expressjs/express-paginate`: N/A
|
||||
- `expressjs/express`: @wesleytodd
|
||||
- `expressjs/expressjs.com`: @crandmck, @jonchurch
|
||||
- `expressjs/flash`: N/A
|
||||
- `expressjs/generator`: @wesleytodd
|
||||
- `expressjs/method-override`: N/A
|
||||
- `expressjs/morgan`: @jonchurch
|
||||
- `expressjs/multer`: @LinusU
|
||||
- `expressjs/response-time`: @blakeembrey
|
||||
- `expressjs/serve-favicon`: N/A
|
||||
- `expressjs/serve-index`: N/A
|
||||
- `expressjs/serve-static`: N/A
|
||||
- `expressjs/session`: N/A
|
||||
- `expressjs/statusboard`: @wesleytodd
|
||||
- `expressjs/timeout`: N/A
|
||||
- `expressjs/vhost`: N/A
|
||||
- `jshttp/accepts`: @blakeembrey
|
||||
- `jshttp/basic-auth`: @blakeembrey
|
||||
- `jshttp/compressible`: @blakeembrey
|
||||
- `jshttp/content-disposition`: @blakeembrey
|
||||
- `jshttp/content-type`: @blakeembrey
|
||||
- `jshttp/cookie`: @wesleytodd
|
||||
- `jshttp/etag`: @blakeembrey
|
||||
- `jshttp/forwarded`: @blakeembrey
|
||||
- `jshttp/fresh`: @blakeembrey
|
||||
- `jshttp/http-assert`: @wesleytodd, @jonchurch
|
||||
- `jshttp/http-errors`: @wesleytodd, @jonchurch
|
||||
- `jshttp/media-typer`: @blakeembrey
|
||||
- `jshttp/methods`: @blakeembrey
|
||||
- `jshttp/mime-db`: @blakeembrey, @UlisesGascon
|
||||
- `jshttp/mime-types`: @blakeembrey, @UlisesGascon
|
||||
- `jshttp/negotiator`: @blakeembrey
|
||||
- `jshttp/on-finished`: @wesleytodd
|
||||
- `jshttp/on-headers`: @blakeembrey
|
||||
- `jshttp/proxy-addr`: @wesleytodd
|
||||
- `jshttp/range-parser`: @blakeembrey
|
||||
- `jshttp/statuses`: @blakeembrey
|
||||
- `jshttp/type-is`: @blakeembrey
|
||||
- `jshttp/vary`: @blakeembrey
|
||||
- `pillarjs/cookies`: @blakeembrey
|
||||
- `pillarjs/csrf`: N/A
|
||||
- `pillarjs/encodeurl`: @blakeembrey
|
||||
- `pillarjs/finalhandler`: @wesleytodd
|
||||
- `pillarjs/hbs`: N/A
|
||||
- `pillarjs/multiparty`: @blakeembrey
|
||||
- `pillarjs/parseurl`: @blakeembrey
|
||||
- `pillarjs/path-to-regexp`: @blakeembrey
|
||||
- `pillarjs/request`: @wesleytodd
|
||||
- `pillarjs/resolve-path`: @blakeembrey
|
||||
- `pillarjs/router`: @blakeembrey
|
||||
- `pillarjs/send`: @blakeembrey
|
||||
- `pillarjs/understanding-csrf`: N/A
|
||||
|
||||
### Current Initiative Captains
|
||||
|
||||
- Triage team [ref](https://github.com/expressjs/discussions/issues/227): @UlisesGascon
|
||||
3217
History.md
6
LICENSE
@@ -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-2011 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.
|
||||
35
Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
TESTS = $(shell find test/*.test.js)
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso \
|
||||
-I lib \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
|
||||
docs: $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@markdown $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
> $@
|
||||
|
||||
site:
|
||||
rm -fr /tmp/docs \
|
||||
&& cp -fr docs /tmp/docs \
|
||||
&& git checkout gh-pages \
|
||||
&& cp -fr /tmp/docs/* . \
|
||||
&& echo "done"
|
||||
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: site test test-cov docs docclean
|
||||
125
Readme-Guide.md
@@ -1,125 +0,0 @@
|
||||
# README guidelines
|
||||
|
||||
Every module in the expressjs, pillarjs, and jshttp organizations should have
|
||||
a README file named `README.md`. The purpose of the README is to:
|
||||
|
||||
- Explain the purpose of the module and how to use it.
|
||||
- Act as a landing page (both on GitHub and npmjs.com) for the module to help
|
||||
people find it via search. Middleware module READMEs are also incorporated
|
||||
into https://expressjs.com/en/resources/middleware.html.
|
||||
- Encourage community contributions and participation.
|
||||
|
||||
Use the [README template](https://github.com/expressjs/express/wiki/README-template)
|
||||
to quickly create a new README file.
|
||||
|
||||
## Top-level items
|
||||
|
||||
**Badges** (optional): At the very top (with no subheading), include any
|
||||
applicable badges, such as npm version/downloads, build status, test coverage,
|
||||
and so on. Badges should resolve properly (not display a broken image).
|
||||
|
||||
Possible badges include:
|
||||
- npm version: `[![NPM Version][npm-image]][npm-url]`
|
||||
- npm downloads: `[![NPM Downloads][downloads-image]][downloads-url]`
|
||||
- Build status: `[![Build Status][travis-image]][travis-url]`
|
||||
- Test coverage: `[![Test Coverage][coveralls-image]][coveralls-url]`
|
||||
- Tips: `[![Gratipay][gratipay-image]][gratipay-url]`
|
||||
|
||||
**Summary**: Following badges, provide a one- or two-sentence description of
|
||||
what the module does. This should be the same as the npmjs.org blurb (which
|
||||
comes from the description property of `package.json`). Since npm doesn't
|
||||
handle markdown for the blurb, avoid using markdown in the summary sentence.
|
||||
|
||||
**TOC** (Optional): For longer READMEs, provide a table of contents that has
|
||||
a relative link to each section. A tool such as
|
||||
[doctoc](https://www.npmjs.com/package/doctoc) makes it very easy to generate
|
||||
a TOC.
|
||||
|
||||
## Overview
|
||||
|
||||
Optionally, include a section of one or two paragraphs with more high-level
|
||||
information on what the module does, what problems it solves, why one would
|
||||
use it and how. Don't just repeat what's in the summary.
|
||||
|
||||
## Installation
|
||||
|
||||
Required. This section is typically just:
|
||||
|
||||
```sh
|
||||
$ npm install module-name
|
||||
```
|
||||
|
||||
But include any other steps or requirements.
|
||||
|
||||
NOTE: Use the `sh` code block to make the shell command display properly on
|
||||
the website.
|
||||
|
||||
## Basic use
|
||||
|
||||
- Provide a general description of how to use the module with code sample.
|
||||
Include any important caveats or restrictions.
|
||||
- Explain the most common use cases.
|
||||
- Optional: a simple "hello world" type example (where applicable). This
|
||||
example is in addition to the more comprehensive [example section](#examples)
|
||||
later.
|
||||
|
||||
## API
|
||||
|
||||
Provide complete API documentation.
|
||||
|
||||
Formatting conventions: Each function is listed in a 3rd-level heading (`###`),
|
||||
like this:
|
||||
|
||||
```
|
||||
### Function_name(arg, options [, optional_arg] ... )
|
||||
```
|
||||
|
||||
**Options objects**
|
||||
|
||||
For arguments that are objects (for example, options object), describe the
|
||||
properties in a table, as follows. This matches the formatting used in the
|
||||
[Express API docs](https://expressjs.com/en/4x/api.html).
|
||||
|
||||
|Property | Description | Type | Default|
|
||||
|----------|-----------|------------|-------------|
|
||||
|Name of the property in `monospace`. | Brief description | String, Number, Boolean, etc. | If applicable.|
|
||||
|
||||
If all the properties are required (i.e. there are no defaults), then you
|
||||
can omit the default column.
|
||||
|
||||
Instead of very lengthy descriptions, link out to subsequent paragraphs for
|
||||
more detailed explanation of specific cases (e.g. "When this property is set
|
||||
to 'foobar', xyz happens; see <link to following section >.)
|
||||
|
||||
If there are options properties that are themselves options, use additional
|
||||
tables. See [`trust proxy` and `etag` properties](https://expressjs.com/en/4x/api.html#app.settings.table).
|
||||
|
||||
## Examples
|
||||
|
||||
Every README should have at least one example; ideally more. For code samples,
|
||||
be sure to use the `js` code block, for proper display in the website, e.g.:
|
||||
|
||||
```js
|
||||
var csurf = require('csurf')
|
||||
...
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
What tests are included.
|
||||
|
||||
How to run them.
|
||||
|
||||
The convention for running tests is `npm test`. All our projects should follow
|
||||
this convention.
|
||||
|
||||
## Contributors
|
||||
|
||||
Names of module "owners" (lead developers) and other developers who have
|
||||
contributed.
|
||||
|
||||
## License
|
||||
|
||||
Link to the license, with a short description of what it is, e.g. "MIT" or
|
||||
whatever. Ideally, avoid putting the license text directly in the README; link
|
||||
to it instead.
|
||||
321
Readme.md
@@ -1,260 +1,143 @@
|
||||
[](http://expressjs.com/)
|
||||
|
||||
**Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org).**
|
||||
|
||||
**This project has a [Code of Conduct][].**
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Installation](#Installation)
|
||||
* [Features](#Features)
|
||||
* [Docs & Community](#docs--community)
|
||||
* [Quick Start](#Quick-Start)
|
||||
* [Running Tests](#Running-Tests)
|
||||
* [Philosophy](#Philosophy)
|
||||
* [Examples](#Examples)
|
||||
* [Contributing to Express](#Contributing)
|
||||
* [TC (Technical Committee)](#tc-technical-committee)
|
||||
* [Triagers](#triagers)
|
||||
* [License](#license)
|
||||
|
||||
|
||||
[![NPM Version][npm-version-image]][npm-url]
|
||||
[![NPM Install Size][npm-install-size-image]][npm-install-size-url]
|
||||
[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
|
||||
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
|
||||
|
||||
|
||||
```js
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('Hello World')
|
||||
})
|
||||
|
||||
app.listen(3000)
|
||||
```
|
||||
# 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');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Installation
|
||||
|
||||
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||
[npm registry](https://www.npmjs.com/).
|
||||
$ npm install express
|
||||
|
||||
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
|
||||
Node.js 0.10 or higher is required.
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
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).
|
||||
$ npm install -g express
|
||||
|
||||
Installation is done using the
|
||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||
## Quick Start
|
||||
|
||||
```console
|
||||
$ npm install express
|
||||
```
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
|
||||
Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
|
||||
for more information.
|
||||
Create the app:
|
||||
|
||||
$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install -d
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app.js
|
||||
|
||||
## 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](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
|
||||
* [#express](https://web.libera.chat/#express) on [Libera Chat](https://libera.chat) IRC
|
||||
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
|
||||
* Visit the [Wiki](https://github.com/expressjs/express/wiki)
|
||||
* [Google Group](https://groups.google.com/group/express-js) for discussion
|
||||
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).
|
||||
## 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
|
||||
|
||||
```console
|
||||
$ npm install -g express-generator@4
|
||||
```
|
||||
* #express on freenode
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support
|
||||
* [express-params](https://github.com/visionmedia/express-params) param pre-condition functions
|
||||
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
|
||||
* 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)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* Screencast - [Introduction](http://bit.ly/eRYu0O)
|
||||
* Screencast - [View Partials](http://bit.ly/dU13Fx)
|
||||
* Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH)
|
||||
* Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs)
|
||||
|
||||
Create the app:
|
||||
## Node Compatibility
|
||||
|
||||
```console
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
```
|
||||
Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
|
||||
Install dependencies:
|
||||
Express 2.x is compatible with node 0.4.x and connect 1.x
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
```
|
||||
## Viewing Examples
|
||||
|
||||
Start the server:
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
```console
|
||||
$ npm start
|
||||
```
|
||||
$ npm install
|
||||
|
||||
View the website at: http://localhost:3000
|
||||
then run whichever tests you want:
|
||||
|
||||
## Philosophy
|
||||
$ node examples/jade/app.js
|
||||
|
||||
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.
|
||||
## Running Tests
|
||||
|
||||
Express does not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
|
||||
you can quickly craft your perfect framework.
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
|
||||
## Examples
|
||||
$ npm install
|
||||
|
||||
To view the examples, clone the Express repo and install the dependencies:
|
||||
then run the tests:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/expressjs/express.git --depth 1
|
||||
$ cd express
|
||||
$ npm install
|
||||
```
|
||||
$ make test
|
||||
|
||||
Then run whichever example you want:
|
||||
## License
|
||||
|
||||
```console
|
||||
$ node examples/content-negotiation
|
||||
```
|
||||
(The MIT License)
|
||||
|
||||
## Contributing
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
[![Linux Build][github-actions-ci-image]][github-actions-ci-url]
|
||||
[![Windows Build][appveyor-image]][appveyor-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
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:
|
||||
|
||||
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!
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
See the [Contributing Guide](Contributing.md) 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, then run `npm test`:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
$ npm test
|
||||
```
|
||||
|
||||
## People
|
||||
|
||||
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**
|
||||
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
|
||||
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
|
||||
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
|
||||
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
|
||||
* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
|
||||
* [0ss](https://github.com/0ss) - **Salah**
|
||||
* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
|
||||
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
|
||||
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
|
||||
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
|
||||
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
|
||||
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
|
||||
|
||||
<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**
|
||||
</details>
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/express/master?label=windows
|
||||
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
|
||||
[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master
|
||||
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
|
||||
[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=linux
|
||||
[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
|
||||
[npm-downloads-image]: https://badgen.net/npm/dm/express
|
||||
[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
|
||||
[npm-install-size-image]: https://badgen.net/packagephobia/install/express
|
||||
[npm-install-size-url]: https://packagephobia.com/result?p=express
|
||||
[npm-url]: https://npmjs.org/package/express
|
||||
[npm-version-image]: https://badgen.net/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/express/blob/master/Code-Of-Conduct.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.
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
# Express Release Process
|
||||
|
||||
This document contains the technical aspects of the Express release process. The
|
||||
intended audience is those who have been authorized by the Express Technical
|
||||
Committee (TC) to create, promote and sign official release builds for Express,
|
||||
as npm packages hosted on https://npmjs.com/package/express.
|
||||
|
||||
## Who can make releases?
|
||||
|
||||
Release authorization is given by the Express TC. Once authorized, an individual
|
||||
must have the following access permissions:
|
||||
|
||||
### 1. Github release access
|
||||
|
||||
The individual making the release will need to be a member of the
|
||||
expressjs/express team with Write permission level so they are able to tag the
|
||||
release commit and push changes to the expressjs/express repository
|
||||
(see Steps 4 and 5).
|
||||
|
||||
### 2. npmjs.com release access
|
||||
|
||||
The individual making the release will need to be made an owner on the
|
||||
`express` package on npmjs.com so they are able to publish the release
|
||||
(see Step 6).
|
||||
|
||||
## How to publish a release
|
||||
|
||||
Before publishing, the following preconditions should be met:
|
||||
|
||||
- A release proposal issue or tracking pull request (see "Proposal branch"
|
||||
below) will exist documenting:
|
||||
- the proposed changes
|
||||
- the type of release: patch, minor or major
|
||||
- the version number (according to semantic versioning - http://semver.org)
|
||||
- The proposed changes should be complete.
|
||||
|
||||
There are two main release flows: patch and non-patch.
|
||||
|
||||
The patch flow is for making **patch releases**. As per semantic versioning,
|
||||
patch releases are for simple changes, eg: typo fixes, patch dependency updates,
|
||||
and simple/low-risk bug fixes. Every other type of change is made via the
|
||||
non-patch flow.
|
||||
|
||||
### Branch terminology
|
||||
|
||||
"Master branch"
|
||||
|
||||
- There is a branch in git used for the current major version of Express, named
|
||||
`master`.
|
||||
- This branch contains the completed commits for the next patch release of the
|
||||
current major version.
|
||||
- Releases for the current major version are published from this branch.
|
||||
|
||||
"Version branch"
|
||||
|
||||
- For any given major version of Express (current, previous or next) there is
|
||||
a branch in git for that release named `<major-version>.x` (eg: `4.x`).
|
||||
- This branch points to the commit of the latest tag for the given major version.
|
||||
|
||||
"Release branch"
|
||||
|
||||
- For any given major version of Express, there is a branch used for publishing
|
||||
releases.
|
||||
- For the current major version of Express, the release branch is the
|
||||
"Master branch" named `master`.
|
||||
- For all other major versions of Express, the release branch is the
|
||||
"Version branch" named `<major-version>.x`.
|
||||
|
||||
"Proposal branch"
|
||||
|
||||
- A branch in git representing a proposed new release of Express. This can be a
|
||||
minor or major release, named `<major-version>.0` for a major release,
|
||||
`<major-version>.<minor-version>` for a minor release.
|
||||
- A tracking pull request should exist to document the proposed release,
|
||||
targeted at the appropriate release branch. Prior to opening the tracking
|
||||
pull request the content of the release may have be discussed in an issue.
|
||||
- This branch contains the commits accepted so far that implement the proposal
|
||||
in the tracking pull request.
|
||||
|
||||
### Pre-release Versions
|
||||
|
||||
Alpha and Beta releases are made from a proposal branch. The version number should be
|
||||
incremented to the next minor version with a `-beta` or `-alpha` suffix.
|
||||
For example, if the next beta release is `5.0.1`, the beta release would be `5.0.1-beta.0`.
|
||||
The pre-releases are unstable and not suitable for production use.
|
||||
|
||||
### Patch flow
|
||||
|
||||
In the patch flow, simple changes are committed to the release branch which
|
||||
acts as an ever-present branch for the next patch release of the associated
|
||||
major version of Express.
|
||||
|
||||
The release branch is usually kept in a state where it is ready to release.
|
||||
Releases are made when sufficient time or change has been made to warrant it.
|
||||
This is usually proposed and decided using a github issue.
|
||||
|
||||
### Non-patch flow
|
||||
|
||||
In the non-patch flow, changes are committed to a temporary proposal branch
|
||||
created specifically for that release proposal. The branch is based on the
|
||||
most recent release of the major version of Express that the release targets.
|
||||
|
||||
Releases are made when all the changes on a proposal branch are complete and
|
||||
approved. This is done by merging the proposal branch into the release branch
|
||||
(using a fast-forward merge), tagging it with the new version number and
|
||||
publishing the release package to npmjs.com.
|
||||
|
||||
### Flow
|
||||
|
||||
Below is a detailed description of the steps to publish a release.
|
||||
|
||||
#### Step 1. Check the release is ready to publish
|
||||
|
||||
Check any relevant information to ensure the release is ready, eg: any
|
||||
milestone, label, issue or tracking pull request for the release. The release
|
||||
is ready when all proposed code, tests and documentation updates are complete
|
||||
(either merged, closed or re-targeted to another release).
|
||||
|
||||
#### Step 2. (Non-patch flow only) Merge the proposal branch into the release branch
|
||||
|
||||
In the patch flow: skip this step.
|
||||
|
||||
In the non-patch flow:
|
||||
```sh
|
||||
$ git checkout <release-branch>
|
||||
$ git merge --ff-only <proposal-branch>
|
||||
```
|
||||
|
||||
<release-branch> - see "Release branch" of "Branches" above.
|
||||
<proposal-branch> - see "Proposal branch" of "Non-patch flow" above.
|
||||
|
||||
**NOTE:** You may need to rebase the proposal branch to allow a fast-forward
|
||||
merge. Using a fast-forward merge keeps the history clean as it does
|
||||
not introduce merge commits.
|
||||
|
||||
### Step 3. Update the History.md and package.json to the new version number
|
||||
|
||||
The changes so far for the release should already be documented under the
|
||||
"unreleased" section at the top of the History.md file, as per the usual
|
||||
development practice. Change "unreleased" to the new release version / date.
|
||||
Example diff fragment:
|
||||
|
||||
```diff
|
||||
-unreleased
|
||||
-==========
|
||||
+4.13.3 / 2015-08-02
|
||||
+===================
|
||||
```
|
||||
|
||||
The version property in the package.json should already contain the version of
|
||||
the previous release. Change it to the new release version.
|
||||
|
||||
Commit these changes together under a single commit with the message set to
|
||||
the new release version (eg: `4.13.3`):
|
||||
|
||||
```sh
|
||||
$ git checkout <release-branch>
|
||||
<..edit files..>
|
||||
$ git add History.md package.json
|
||||
$ git commit -m '<version-number>'
|
||||
```
|
||||
|
||||
### Step 4. Identify and tag the release commit with the new release version
|
||||
|
||||
Create a lightweight tag (rather than an annotated tag) named after the new
|
||||
release version (eg: `4.13.3`).
|
||||
|
||||
```sh
|
||||
$ git tag <version-number>
|
||||
```
|
||||
|
||||
### Step 5. Push the release branch changes and tag to github
|
||||
|
||||
The branch and tag should be pushed directly to the main repository
|
||||
(https://github.com/expressjs/express).
|
||||
|
||||
```sh
|
||||
$ git push origin <release-branch>
|
||||
$ git push origin <version-number>
|
||||
```
|
||||
|
||||
### Step 6. Publish to npmjs.com
|
||||
|
||||
Ensure your local working copy is completely clean (no extra or changed files).
|
||||
You can use `git status` for this purpose.
|
||||
|
||||
```sh
|
||||
$ npm login <npm-username>
|
||||
$ npm publish
|
||||
```
|
||||
|
||||
**NOTE:** The version number to publish will be picked up automatically from
|
||||
package.json.
|
||||
|
||||
### Step 7. Update documentation website
|
||||
|
||||
The documentation website https://expressjs.com/ documents the current release version in various places. For a new release:
|
||||
1. Change the value of `current_version` in https://github.com/expressjs/expressjs.com/blob/gh-pages/_data/express.yml to match the latest version number.
|
||||
2. Add a new section to the change log. For example, for a 4.x release, https://github.com/expressjs/expressjs.com/blob/gh-pages/en/changelog/4x.md,
|
||||
56
Security.md
@@ -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 the lead maintainer in the Readme.md file.
|
||||
|
||||
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.
|
||||
@@ -1,70 +0,0 @@
|
||||
# Express Triager Guide
|
||||
|
||||
## Issue Triage Process
|
||||
|
||||
When a new issue or pull request is opened the issue will be labeled with `needs triage`.
|
||||
If a triage team member is available they can help make sure all the required information
|
||||
is provided. Depending on the issue or PR there are several next labels they can add for further
|
||||
classification:
|
||||
|
||||
* `needs triage`: This can be kept if the triager is unsure which next steps to take
|
||||
* `awaiting more info`: If more info has been requested from the author, apply this label.
|
||||
* `bug`: Issues that present a reasonable conviction there is a reproducible bug.
|
||||
* `enhancement`: Issues that are found to be a reasonable candidate feature additions.
|
||||
|
||||
If the issue is a question or discussion, it should be moved to GitHub Discussions.
|
||||
|
||||
### Moving Discussions and Questions to GitHub Discussions
|
||||
|
||||
For issues labeled with `question` or `discuss`, it is recommended to move them to GitHub Discussions instead:
|
||||
|
||||
* **Questions**: User questions that do not appear to be bugs or enhancements should be moved to GitHub Discussions.
|
||||
* **Discussions**: Topics for discussion should be moved to GitHub Discussions. If the discussion leads to a new feature or bug identification, it can be moved back to Issues.
|
||||
|
||||
In all cases, issues may be closed by maintainers if they don't receive a timely response when
|
||||
further information is sought, or when additional questions are asked.
|
||||
|
||||
## Approaches and Best Practices for getting into triage contributions
|
||||
|
||||
Review the organization's [StatusBoard](https://expressjs.github.io/statusboard/),
|
||||
pay special attention to these columns: stars, watchers, open issues, and contributors.
|
||||
This gives you a general idea about the criticality and health of the repository.
|
||||
Pick a few projects based on that criteria, your interests, and skills (existing or aspiring).
|
||||
|
||||
Review the project's contribution guideline if present. In a nutshell,
|
||||
commit to the community's standards and values. Review the
|
||||
documentation, for most of the projects it is just the README.md, and
|
||||
make sure you understand the key APIs, semantics, configurations, and use cases.
|
||||
|
||||
It might be helpful to write your own test apps to re-affirm your
|
||||
understanding of the key functions. This may identify some gaps in
|
||||
documentation, record those as they might be good PR's to open.
|
||||
Skim through the issue backlog; identify low hanging issues and mostly new ones.
|
||||
From those, attempt to recreate issues based on the OP description and
|
||||
ask questions if required. No question is a bad question!
|
||||
|
||||
## Removal of Triage Role
|
||||
|
||||
There are a few cases where members can be removed as triagers:
|
||||
|
||||
- Breaking the CoC or project contributor guidelines
|
||||
- Abuse or misuse of the role as deemed by the TC
|
||||
- Lack of participation for more than 6 months
|
||||
|
||||
If any of these happen we will discuss as a part of the triage portion of the regular TC meetings.
|
||||
If you have questions feel free to reach out to any of the TC members.
|
||||
|
||||
## Other Helpful Hints:
|
||||
|
||||
- Everyone is welcome to attend the [Express Technical Committee Meetings](https://github.com/expressjs/discussions#expressjs-tc-meetings), and as a triager, it might help to get a better idea of what's happening with the project.
|
||||
- When exploring the module's functionality there are a few helpful steps:
|
||||
- Turn on `DEBUG=*` (see https://www.npmjs.com/package/debug) to get detailed log information
|
||||
- It is also a good idea to do live debugging to follow the control flow, try using `node --inspect`
|
||||
- It is a good idea to make at least one pass of reading through the entire source
|
||||
- When reviewing the list of open issues there are some common types and suggested actions:
|
||||
- New/unattended issues or simple questions: A good place to start
|
||||
- Hard bugs & ongoing discussions: always feel free to chime in and help
|
||||
- Issues that imply gaps in the documentation: open PRs with changes or help the user to do so
|
||||
- For recurring issues, it is helpful to create functional examples to demonstrate (publish as gists or a repo)
|
||||
- Review and identify the maintainers. If necessary, at-mention one or more of them if you are unsure what to do
|
||||
- Make sure all your interactions are professional, welcoming, and respectful to the parties involved.
|
||||
@@ -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
|
||||
@@ -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`.
|
||||
@@ -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);
|
||||
@@ -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
|
||||
417
bin/express
Executable file
@@ -0,0 +1,417 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, exec = require('child_process').exec;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.4.3';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
*/
|
||||
|
||||
var sessions = false;
|
||||
|
||||
/**
|
||||
* CSS engine to utilize.
|
||||
*/
|
||||
|
||||
var cssEngine;
|
||||
|
||||
/**
|
||||
* Template engine to utilize.
|
||||
*/
|
||||
|
||||
var templateEngine = 'jade';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\n'
|
||||
+ ' Usage: express [options] [path]\n'
|
||||
+ '\n'
|
||||
+ ' Options:\n'
|
||||
+ ' -s, --sessions add session support\n'
|
||||
+ ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
|
||||
+ ' -c, --css <engine> add stylesheet <engine> support (less|sass|stylus). default=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;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
*/
|
||||
|
||||
var less = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default sass template.
|
||||
*/
|
||||
|
||||
var sass = [
|
||||
'body'
|
||||
, ' :padding 50px'
|
||||
, ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' :color #00B7FF'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
*/
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color: #00B7FF'
|
||||
].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.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}{css}'
|
||||
, ' app.use(app.router);'
|
||||
, ' app.use(express.static(__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\', {'
|
||||
, ' title: \'Express\''
|
||||
, ' });'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.listen(3000);'
|
||||
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
|
||||
, ''
|
||||
].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) {
|
||||
process.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 + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
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', 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;
|
||||
}
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (cssEngine) {
|
||||
case 'sass':
|
||||
case 'less':
|
||||
app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', sessions
|
||||
? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', templateEngine);
|
||||
|
||||
// package.json
|
||||
var json = '{\n';
|
||||
json += ' "name": "application-name"\n';
|
||||
json += ' , "version": "0.0.1"\n';
|
||||
json += ' , "private": true\n';
|
||||
json += ' , "dependencies": {\n';
|
||||
json += ' "express": "' + version + '"\n';
|
||||
if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\n';
|
||||
if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\n';
|
||||
json += ' }\n';
|
||||
json += '}';
|
||||
|
||||
|
||||
write(path + '/package.json', json);
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 && 'ENOENT' != err.code) 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[36mcreate\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) {
|
||||
// prompt
|
||||
if (' ' == msg[msg.length - 1]) {
|
||||
process.stdout.write(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
// stdin
|
||||
process.stdin.setEncoding('ascii');
|
||||
process.stdin.once('data', function(data){
|
||||
fn(data);
|
||||
}).resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[36mcreate\x1b[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function abort(str) {
|
||||
console.error(str);
|
||||
process.exit(1);
|
||||
}
|
||||
246
docs/applications.html
Normal file
@@ -0,0 +1,246 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
47
docs/applications.md
Normal 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.
|
||||
|
||||
[](http://learnboost.com)
|
||||
|
||||
[Storify](http://storify.com) lets you turn what people post on social media websites into compelling stories.
|
||||
|
||||
[](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.
|
||||
|
||||
[](http://pakistansurvey.org)
|
||||
|
||||
[Markup.IO](http://markup.io) allows you to draw directly on _any_ website, then share with others to share your thoughts.
|
||||
|
||||
[](http://markup.io)
|
||||
|
||||
[Scrabb.ly](http://scrabb.ly) is a massively multiplayer scrabble game initially created for the [Node Knockout](http://nodeknockout.com/) competition.
|
||||
|
||||
[](http://scrabb.ly)
|
||||
|
||||
[ClickDummy](http://clickdummy.net/) is a rapid mockup prototyping application for designers and dummies.
|
||||
|
||||
[](http://clickdummy.net)
|
||||
|
||||
[Node Knockout](http://nodeknockout.com) organized the first ever node-specific competition with hundreds of contestants.
|
||||
|
||||
[](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.
|
||||
|
||||
[](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!
|
||||
|
||||
[](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.
|
||||
|
||||
[](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).
|
||||
240
docs/contrib.html
Normal file
@@ -0,0 +1,240 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
<h3>Development Dependencies</h3>
|
||||
|
||||
<p>First install the dev dependencies by executing the following command in the repo’s directory:</p>
|
||||
|
||||
<pre><code>$ npm install
|
||||
</code></pre>
|
||||
|
||||
<h3>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>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>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>
|
||||
</body>
|
||||
</html>
|
||||
37
docs/contrib.md
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
First install the dev dependencies by executing the following command in the repo's directory:
|
||||
|
||||
$ npm install
|
||||
|
||||
### 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.
|
||||
216
docs/executable.html
Normal file
@@ -0,0 +1,216 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre><code>express [options] [PATH]
|
||||
</code></pre>
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<p>The <em>express</em> 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>Options</h2>
|
||||
|
||||
<pre><code> -s, --sessions Add session support
|
||||
-t, --template ENGINE Add template ENGINE support (jade|ejs). Defaults to jade
|
||||
-c, --css ENGINE Add stylesheet ENGINE support (less|sass|stylus). Defaults to plain css
|
||||
-v, --version Output framework version
|
||||
-h, --help Output help information
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
21
docs/executable.md
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
## Synopsis
|
||||
|
||||
express [options] [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
|
||||
-t, --template ENGINE Add template ENGINE support (jade|ejs). Defaults to jade
|
||||
-c, --css ENGINE Add stylesheet ENGINE support (less|sass|stylus). Defaults to plain css
|
||||
-v, --version Output framework version
|
||||
-h, --help Output help information
|
||||
|
||||
|
||||
|
||||
1807
docs/guide.html
Normal file
1424
docs/guide.md
Normal file
BIN
docs/images/apps/clickdummy.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
docs/images/apps/developmentseed.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
docs/images/apps/e-resistable.png
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
docs/images/apps/learnboost.png
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
docs/images/apps/markupio.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
docs/images/apps/nodeko.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
docs/images/apps/opowerjobs.png
Normal file
|
After Width: | Height: | Size: 200 KiB |
BIN
docs/images/apps/scrabbly.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
docs/images/apps/storify.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
docs/images/apps/toptwittertrends.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
docs/images/apps/widescript.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
docs/images/bg.jpg
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
docs/images/bg.tile.jpg
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/images/logo.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
docs/images/top.png
Normal file
|
After Width: | Height: | Size: 143 B |
266
docs/index.html
Normal file
@@ -0,0 +1,266 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
<pre><code>var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h2>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>Application mounting</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>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>Third-Party Modules</h2>
|
||||
|
||||
<p>The following modules compliment or extend Express directly:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://github.com/visionmedia/express-resource">express-resource</a> provides resourceful routing</li>
|
||||
<li><a href="http://github.com/visionmedia/express-messages">express-messages</a> flash message notification rendering</li>
|
||||
<li><a href="http://github.com/visionmedia/express-configuration">express-configure</a> async configuration support (load settings from redis etc)</li>
|
||||
<li><a href="http://github.com/visionmedia/express-namespace">express-namespace</a> namespaced routing support</li>
|
||||
<li><a href="http://github.com/visionmedia/express-expose">express-expose</a> expose objects, functions, modules and more to client-side js</li>
|
||||
<li><a href="https://github.com/visionmedia/express-params">express-params</a> app.param() extensions</li>
|
||||
<li><a href="https://github.com/LearnBoost/express-mongoose">express-mongoose</a> plugin for easy rendering of Mongoose async Query results</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>More Information</h2>
|
||||
|
||||
<ul>
|
||||
<li>#express on freenode</li>
|
||||
<li>Follow <a href="http://twitter.com/tjholowaychuk">tjholowaychuk</a> on twitter for updates</li>
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>Visit the <a href="http://github.com/visionmedia/express/wiki">Wiki</a></li>
|
||||
<li><a href="http://hideyukisaito.com/doc/expressjs/">日本語ドキュメンテーション</a> by <a href="https://github.com/hideyukisaito">hideyukisaito</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eRYu0O">Introduction</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/dU13Fx">View Partials</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/hX4IaH">Route Specific Middleware</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eNqmVs">Route Path Placeholder Preconditions</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
53
docs/index.md
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
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
|
||||
* Application mounting
|
||||
* 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))
|
||||
|
||||
## Third-Party Modules
|
||||
|
||||
The following modules compliment or extend Express directly:
|
||||
|
||||
* [express-resource](http://github.com/visionmedia/express-resource) provides resourceful routing
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash message notification rendering
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support (load settings from redis etc)
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced routing support
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js
|
||||
* [express-params](https://github.com/visionmedia/express-params) app.param() extensions
|
||||
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
|
||||
|
||||
## More Information
|
||||
|
||||
* \#express on freenode
|
||||
* 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)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
4
docs/layout/foot.html
Normal file
@@ -0,0 +1,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
193
docs/layout/head.html
Normal file
@@ -0,0 +1,193 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
394
docs/migrate.html
Normal file
@@ -0,0 +1,394 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
<h3>Express 1.x to 2.x Migration</h3>
|
||||
|
||||
<h3>HTTPS</h3>
|
||||
|
||||
<p> Creating an HTTPS server is simply, simply pass the TLS options to <em>express.createServer()</em>:</p>
|
||||
|
||||
<pre><code> var app = express.createServer({
|
||||
key: ...
|
||||
, cert: ...
|
||||
});
|
||||
|
||||
app.listen(443);
|
||||
</code></pre>
|
||||
|
||||
<h3>req.header() Referrer</h3>
|
||||
|
||||
<p> Previously if anyone was doing something similar to:</p>
|
||||
|
||||
<pre><code> req.headers.referrer || req.headers.referer
|
||||
req.header('Referrer') || req.header('Referer')
|
||||
</code></pre>
|
||||
|
||||
<p> With the new special-case we may now simply use <em>Referrer</em> which will return either if defined:</p>
|
||||
|
||||
<pre><code> req.header('Referrer')
|
||||
</code></pre>
|
||||
|
||||
<h3>res.local(name, val)</h3>
|
||||
|
||||
<p> Previously all local variables had to be passed to <em>res.render()</em>, or either <em>app.helpers()</em> or <em>app.dynamicHelpers()</em>, now we may do this at the request-level progressively. The <em>res.local()</em> method accepts a <em>name</em> and <em>val</em>, however the locals passed to <em>res.render()</em> will take precedence.</p>
|
||||
|
||||
<p> For example we may utilize this feature to create locals in middleware:</p>
|
||||
|
||||
<pre><code> function loadUser(req, res, next) {
|
||||
User.get(req.params.id, function(err, user){
|
||||
res.local('user', user);
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
app.get('/user/:id', loadUser, function(req, res){
|
||||
res.render('user');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3>req.param(name[, defaultValue])</h3>
|
||||
|
||||
<p> Previously only <em>name</em> was accepted, so some of you may have been doing the following:</p>
|
||||
|
||||
<pre><code> var id = req.param('id') || req.user.id;
|
||||
</code></pre>
|
||||
|
||||
<p> The new <em>defaultValue</em> argument can handle this nicely:</p>
|
||||
|
||||
<pre><code> var id = req.param('id', req.user.id);
|
||||
</code></pre>
|
||||
|
||||
<h3>app.helpers() / app.locals()</h3>
|
||||
|
||||
<p> <em>app.locals()</em> is now an alias of <em>app.helpers()</em>, as helpers makes more sense for functions.</p>
|
||||
|
||||
<h3>req.accepts(type)</h3>
|
||||
|
||||
<p> <em>req.accepts()</em> now accepts extensions:</p>
|
||||
|
||||
<pre><code> // Accept: text/html
|
||||
req.accepts('html');
|
||||
req.accepts('.html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/*');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
</code></pre>
|
||||
|
||||
<h3>res.cookie()</h3>
|
||||
|
||||
<p> Previously only directly values could be passed, so for example:</p>
|
||||
|
||||
<pre><code>res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000) });
|
||||
</code></pre>
|
||||
|
||||
<p>However now we have the alternative <em>maxAge</em> property which may be used to set <em>expires</em> relative to <em>Date.now()</em> in milliseconds, so our example above can now become:</p>
|
||||
|
||||
<pre><code>res.cookie('rememberme', 'yes', { maxAge: 900000 });
|
||||
</code></pre>
|
||||
|
||||
<h3>res.download() / res.sendfile()</h3>
|
||||
|
||||
<p> Both of these methods now utilize Connect’s static file server behind the scenes (actually the previous Express code was ported to Connect 1.0). With this change comes a change to the callback as well. Previously the <em>path</em> and <em>stream</em> were passed, however now only an <em>error</em> is passed, when no error has occurred the callback will be invoked indicating that the file transfer is complete. The callback remains optional:</p>
|
||||
|
||||
<pre><code> res.download('/path/to/file');
|
||||
|
||||
res.download('/path/to/file', function(err){
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('transferred');
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p> The <em>stream threshold</em> setting was removed.</p>
|
||||
|
||||
<h3>res.render()</h3>
|
||||
|
||||
<p> Previously locals were passed as a separate key:</p>
|
||||
|
||||
<pre><code> res.render('user', { layout: false, locals: { user: user }});
|
||||
</code></pre>
|
||||
|
||||
<p> In Express 2.0 both the locals and the options are one in the same, meaning you cannot have a local variable named <em>layout</em> as it is reserved for express, however this cleans up the API:</p>
|
||||
|
||||
<pre><code> res.render('user', { layout: false, user: user });
|
||||
</code></pre>
|
||||
|
||||
<h3>res.partial()</h3>
|
||||
|
||||
<p> Express 2.0 adds the <em>res.partial()</em> method, helpful for rendering partial fragments over WebSockets or Ajax requests etc. The API is identical to the <em>partial()</em> calls within views.</p>
|
||||
|
||||
<pre><code> // render a collection of comments
|
||||
res.partial('comment', [comment1, comment2]);
|
||||
|
||||
// render a single comment
|
||||
res.partial('comment', comment);
|
||||
</code></pre>
|
||||
|
||||
<h3>partial() locals</h3>
|
||||
|
||||
<p> Both <em>res.partial()</em> and the <em>partial()</em> functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass <em>user</em> to a partial, along with <em>date</em> like so:</p>
|
||||
|
||||
<pre><code> partial('user', { object: user, locals: { date: new Date }})
|
||||
</code></pre>
|
||||
|
||||
<p>or perhaps if you preferred not to use the inferred name <em>user</em> you may used a local for this as well:</p>
|
||||
|
||||
<pre><code> partial('user', { locals: { user: user, date: new Date }})
|
||||
</code></pre>
|
||||
|
||||
<p> With recent changes to Express 2.x the object passed is now both, so the following is valid for the <em>object</em> option and locals:</p>
|
||||
|
||||
<pre><code> partial('user', { object: user, date: new Date })
|
||||
</code></pre>
|
||||
|
||||
<p> Or the following which is equivalent, however the local var name is explicitly set to <em>user</em> instead of deduced from the filename.</p>
|
||||
|
||||
<pre><code> partial('user', { user: user, date: new Date })
|
||||
</code></pre>
|
||||
|
||||
<p> When a “basic” object aka <em>{}</em> or <em>new Object</em> is passed, it is considered options, otherwise it is considered the <em>object</em>. The following are equivalent:</p>
|
||||
|
||||
<pre><code> partial('user', user);
|
||||
partial('user', { object: user });
|
||||
</code></pre>
|
||||
|
||||
<h3>Template Engine Compliance</h3>
|
||||
|
||||
<p> To comply with Express previously engines needed the following signature:</p>
|
||||
|
||||
<pre><code> engine.render(str, options, function(err){});
|
||||
</code></pre>
|
||||
|
||||
<p> Now they must export a <em>compile()</em> function, returning a function which when called with local variables will render the template. This allows Express to cache the compiled function in memory during production.</p>
|
||||
|
||||
<pre><code> var fn = engine.compile(str, options);
|
||||
fn(locals);
|
||||
</code></pre>
|
||||
|
||||
<h3>View Partial Lookup</h3>
|
||||
|
||||
<p> Previously partials were loaded relative to the now removed <em>view partials</em> directory setting, or by default <em>views/partials</em>, now they are relative to the view calling them, read more on <a href="guide.html#view-lookup">view lookup</a>.</p>
|
||||
|
||||
<h3>Mime Types</h3>
|
||||
|
||||
<p> Express and Connect now utilize the <em>mime</em> module in npm, so to add more use:</p>
|
||||
|
||||
<pre><code> require('mime').define({ 'foo/bar': ['foo', 'bar'] });
|
||||
</code></pre>
|
||||
|
||||
<h3>static() middleware</h3>
|
||||
|
||||
<p> Previously named <code>staticProvider()</code>, the now <code>static()</code> middleware takes a single directory path, followed by options.</p>
|
||||
|
||||
<pre><code> app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
|
||||
</code></pre>
|
||||
|
||||
<p>Previously when using options the <code>root</code> option would be used for this:</p>
|
||||
|
||||
<pre><code> app.use(express.staticProvider({ root: __dirname + '/public', maxAge: oneYear }));
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
177
docs/migrate.md
Normal file
@@ -0,0 +1,177 @@
|
||||
|
||||
### Express 1.x to 2.x Migration
|
||||
|
||||
### HTTPS
|
||||
|
||||
Creating an HTTPS server is simply, simply pass the TLS options to _express.createServer()_:
|
||||
|
||||
var app = express.createServer({
|
||||
key: ...
|
||||
, cert: ...
|
||||
});
|
||||
|
||||
app.listen(443);
|
||||
|
||||
### req.header() Referrer
|
||||
|
||||
Previously if anyone was doing something similar to:
|
||||
|
||||
req.headers.referrer || req.headers.referer
|
||||
req.header('Referrer') || req.header('Referer')
|
||||
|
||||
With the new special-case we may now simply use _Referrer_ which will return either if defined:
|
||||
|
||||
req.header('Referrer')
|
||||
|
||||
### res.local(name, val)
|
||||
|
||||
Previously all local variables had to be passed to _res.render()_, or either _app.helpers()_ or _app.dynamicHelpers()_, now we may do this at the request-level progressively. The _res.local()_ method accepts a _name_ and _val_, however the locals passed to _res.render()_ will take precedence.
|
||||
|
||||
For example we may utilize this feature to create locals in middleware:
|
||||
|
||||
function loadUser(req, res, next) {
|
||||
User.get(req.params.id, function(err, user){
|
||||
res.local('user', user);
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
app.get('/user/:id', loadUser, function(req, res){
|
||||
res.render('user');
|
||||
});
|
||||
|
||||
### req.param(name[, defaultValue])
|
||||
|
||||
Previously only _name_ was accepted, so some of you may have been doing the following:
|
||||
|
||||
var id = req.param('id') || req.user.id;
|
||||
|
||||
The new _defaultValue_ argument can handle this nicely:
|
||||
|
||||
var id = req.param('id', req.user.id);
|
||||
|
||||
### app.helpers() / app.locals()
|
||||
|
||||
_app.locals()_ is now an alias of _app.helpers()_, as helpers makes more sense for functions.
|
||||
|
||||
### req.accepts(type)
|
||||
|
||||
_req.accepts()_ now accepts extensions:
|
||||
|
||||
|
||||
// Accept: text/html
|
||||
req.accepts('html');
|
||||
req.accepts('.html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/*');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
|
||||
### res.cookie()
|
||||
|
||||
Previously only directly values could be passed, so for example:
|
||||
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000) });
|
||||
|
||||
However now we have the alternative _maxAge_ property which may be used to set _expires_ relative to _Date.now()_ in milliseconds, so our example above can now become:
|
||||
|
||||
res.cookie('rememberme', 'yes', { maxAge: 900000 });
|
||||
|
||||
### res.download() / res.sendfile()
|
||||
|
||||
Both of these methods now utilize Connect's static file server behind the scenes (actually the previous Express code was ported to Connect 1.0). With this change comes a change to the callback as well. Previously the _path_ and _stream_ were passed, however now only an _error_ is passed, when no error has occurred the callback will be invoked indicating that the file transfer is complete. The callback remains optional:
|
||||
|
||||
res.download('/path/to/file');
|
||||
|
||||
res.download('/path/to/file', function(err){
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('transferred');
|
||||
}
|
||||
});
|
||||
|
||||
The _stream threshold_ setting was removed.
|
||||
|
||||
### res.render()
|
||||
|
||||
Previously locals were passed as a separate key:
|
||||
|
||||
res.render('user', { layout: false, locals: { user: user }});
|
||||
|
||||
In Express 2.0 both the locals and the options are one in the same, meaning you cannot have a local variable named _layout_ as it is reserved for express, however this cleans up the API:
|
||||
|
||||
res.render('user', { layout: false, user: user });
|
||||
|
||||
### res.partial()
|
||||
|
||||
Express 2.0 adds the _res.partial()_ method, helpful for rendering partial fragments over WebSockets or Ajax requests etc. The API is identical to the _partial()_ calls within views.
|
||||
|
||||
// render a collection of comments
|
||||
res.partial('comment', [comment1, comment2]);
|
||||
|
||||
// render a single comment
|
||||
res.partial('comment', comment);
|
||||
|
||||
### partial() locals
|
||||
|
||||
Both _res.partial()_ and the _partial()_ functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass _user_ to a partial, along with _date_ like so:
|
||||
|
||||
partial('user', { object: user, locals: { date: new Date }})
|
||||
|
||||
or perhaps if you preferred not to use the inferred name _user_ you may used a local for this as well:
|
||||
|
||||
partial('user', { locals: { user: user, date: new Date }})
|
||||
|
||||
With recent changes to Express 2.x the object passed is now both, so the following is valid for the _object_ option and locals:
|
||||
|
||||
partial('user', { object: user, date: new Date })
|
||||
|
||||
Or the following which is equivalent, however the local var name is explicitly set to _user_ instead of deduced from the filename.
|
||||
|
||||
partial('user', { user: user, date: new Date })
|
||||
|
||||
When a "basic" object aka _{}_ or _new Object_ is passed, it is considered options, otherwise it is considered the _object_. The following are equivalent:
|
||||
|
||||
partial('user', user);
|
||||
partial('user', { object: user });
|
||||
|
||||
### Template Engine Compliance
|
||||
|
||||
To comply with Express previously engines needed the following signature:
|
||||
|
||||
engine.render(str, options, function(err){});
|
||||
|
||||
Now they must export a _compile()_ function, returning a function which when called with local variables will render the template. This allows Express to cache the compiled function in memory during production.
|
||||
|
||||
var fn = engine.compile(str, options);
|
||||
fn(locals);
|
||||
|
||||
### View Partial Lookup
|
||||
|
||||
Previously partials were loaded relative to the now removed _view partials_ directory setting, or by default _views/partials_, now they are relative to the view calling them, read more on [view lookup](guide.html#view-lookup).
|
||||
|
||||
### Mime Types
|
||||
|
||||
Express and Connect now utilize the _mime_ module in npm, so to add more use:
|
||||
|
||||
require('mime').define({ 'foo/bar': ['foo', 'bar'] });
|
||||
|
||||
### static() middleware
|
||||
|
||||
Previously named `staticProvider()`, the now `static()` middleware takes a single directory path, followed by options.
|
||||
|
||||
app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
|
||||
|
||||
Previously when using options the `root` option would be used for this:
|
||||
|
||||
app.use(express.staticProvider({ root: __dirname + '/public', maxAge: oneYear }));
|
||||
|
||||
224
docs/screencasts.html
Normal file
@@ -0,0 +1,224 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<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: 75px;
|
||||
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="screencasts.html">Screencasts</a></li>
|
||||
<li><a href="applications.html">Applications</a></li>
|
||||
</ul>
|
||||
<h3>Introduction</h3>
|
||||
|
||||
<p>This introduction screencast covers the basics of Express, and how to get started with your first application.</p>
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=139583' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=139583' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
|
||||
<h3>View Partials</h3>
|
||||
|
||||
<p>In this screencast we work with partials to display a collection of users using the <a href="http://jade-lang.com">Jade</a> template engine, and learn about view path resolution.</p>
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=139591' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=139591' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
|
||||
<h3>Route Specific Middleware</h3>
|
||||
|
||||
<p>In the screencast below we learn about the benefits of route-specific middleware.</p>
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=140296' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=140296' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
|
||||
<h3>Route Param Preconditions</h3>
|
||||
|
||||
<p>Learn about route parameter (<em>/user/:id</em>) pre-conditions, providing automated validation, and loading of data via the named route param segments.</p>
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=140300' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=140300' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
24
docs/screencasts.md
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
### Introduction
|
||||
|
||||
This introduction screencast covers the basics of Express, and how to get started with your first application.
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=139583' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=139583' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
### View Partials
|
||||
|
||||
In this screencast we work with partials to display a collection of users using the [Jade](http://jade-lang.com) template engine, and learn about view path resolution.
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=139591' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=139591' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
### Route Specific Middleware
|
||||
|
||||
In the screencast below we learn about the benefits of route-specific middleware.
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=140296' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=140296' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
|
||||
### Route Param Preconditions
|
||||
|
||||
Learn about route parameter (_/user/:id_) pre-conditions, providing automated validation, and loading of data via the named route param segments.
|
||||
|
||||
<object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=140300' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=140300' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object>
|
||||
@@ -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
|
||||
122
examples/auth/app.js
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, crypto = require('crypto');
|
||||
|
||||
var app = express.createServer(
|
||||
express.bodyParser()
|
||||
, express.cookieParser()
|
||||
, express.session({ secret: 'keyboard cat' })
|
||||
);
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
// 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: hash('foobar', 'randomly-generated-salt')
|
||||
}
|
||||
};
|
||||
|
||||
// Used to generate a hash of the plain-text password + salt
|
||||
|
||||
function hash(msg, key) {
|
||||
return crypto.createHmac('sha256', key).update(msg).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 hash against the pass / salt, if there is a match we
|
||||
// found the user
|
||||
if (user.pass == hash(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');
|
||||
@@ -1,134 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var hash = require('pbkdf2-password')()
|
||||
var path = require('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');
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +1,7 @@
|
||||
<!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;
|
||||
@@ -18,3 +16,6 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
58
examples/blog/app.js
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, messages = require('express-messages');
|
||||
|
||||
var app = module.exports = express.createServer();
|
||||
|
||||
// Config
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// mount hook
|
||||
|
||||
app.mounted(function(other){
|
||||
console.log('ive been mounted!');
|
||||
});
|
||||
|
||||
// Flash message helper provided by express-messages
|
||||
// $ npm install express-messages
|
||||
|
||||
app.dynamicHelpers({
|
||||
messages: messages
|
||||
, base: function(){
|
||||
// return the app's mount-point
|
||||
// so that urls can adjust. For example
|
||||
// if you run this example /post/add works
|
||||
// however if you run the mounting example
|
||||
// it adjusts to /blog/post/add
|
||||
return '/' == app.route ? '' : app.route;
|
||||
}
|
||||
});
|
||||
|
||||
// Middleware
|
||||
|
||||
app.configure(function(){
|
||||
app.use(express.logger('\x1b[33m:method\x1b[0m \x1b[32m:url\x1b[0m :response-time'));
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
require('./routes/site')(app);
|
||||
require('./routes/post')(app);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
67
examples/blog/models/post.js
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
// Fake data store
|
||||
|
||||
var ids = 0
|
||||
, db = {};
|
||||
|
||||
var Post = exports = module.exports = function Post(title, body) {
|
||||
this.id = ++ids;
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
this.createdAt = new Date;
|
||||
};
|
||||
|
||||
Post.prototype.save = function(fn){
|
||||
db[this.id] = this;
|
||||
fn();
|
||||
};
|
||||
|
||||
Post.prototype.validate = function(fn){
|
||||
if (!this.title) return fn(new Error('_title_ required'));
|
||||
if (!this.body) return fn(new Error('_body_ required'));
|
||||
if (this.body.length < 10) {
|
||||
return fn(new Error(
|
||||
'_body_ should be at least **10** characters long, was only _' + this.title.length + '_'));
|
||||
}
|
||||
fn();
|
||||
};
|
||||
|
||||
|
||||
Post.prototype.update = function(data, fn){
|
||||
this.updatedAt = new Date;
|
||||
for (var key in data) {
|
||||
if (undefined != data[key]) {
|
||||
this[key] = data[key];
|
||||
}
|
||||
}
|
||||
this.save(fn);
|
||||
};
|
||||
|
||||
Post.prototype.destroy = function(fn){
|
||||
exports.destroy(this.id, fn);
|
||||
};
|
||||
|
||||
exports.count = function(fn){
|
||||
fn(null, Object.keys(db).length);
|
||||
};
|
||||
|
||||
exports.all = function(fn){
|
||||
var arr = Object.keys(db).reduce(function(arr, id){
|
||||
arr.push(db[id]);
|
||||
return arr;
|
||||
}, []);
|
||||
fn(null, arr);
|
||||
};
|
||||
|
||||
exports.get = function(id, fn){
|
||||
fn(null, db[id]);
|
||||
};
|
||||
|
||||
exports.destroy = function(id, fn) {
|
||||
if (db[id]) {
|
||||
delete db[id];
|
||||
fn();
|
||||
} else {
|
||||
fn(new Error('post ' + id + ' does not exist'));
|
||||
}
|
||||
};
|
||||
58
examples/blog/public/style.css
Normal file
@@ -0,0 +1,58 @@
|
||||
body {
|
||||
font: 13px "Helvetica Neue", Arial, sans-serif;
|
||||
color: #111;
|
||||
padding: 60px 80px;
|
||||
}
|
||||
h1, h2 {
|
||||
color: #c00;
|
||||
}
|
||||
a {
|
||||
color: #c00;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
label {
|
||||
padding: 6px 0;
|
||||
display: block;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
textarea,
|
||||
input {
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
background: #f1f1f1;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
textarea:focus,
|
||||
input:focus {
|
||||
background: #fff;
|
||||
}
|
||||
textarea {
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
}
|
||||
a.edit {
|
||||
margin-left: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.date {
|
||||
font-size: 11px;
|
||||
}
|
||||
#messages ul {
|
||||
padding: 10px;
|
||||
border: 1px solid;
|
||||
}
|
||||
#messages ul li {
|
||||
list-style: none;
|
||||
}
|
||||
#messages ul.info {
|
||||
color: #2EBBE6;
|
||||
background: #F7FBFD;
|
||||
}
|
||||
#messages ul.error {
|
||||
color: #E4250C;
|
||||
background: #FDEAE7;
|
||||
}
|
||||
95
examples/blog/routes/post.js
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var basicAuth = require('../../../lib/express').basicAuth
|
||||
, Post = require('../models/post');
|
||||
|
||||
module.exports = function(app){
|
||||
/**
|
||||
* Apply basic auth to all post related routes
|
||||
*/
|
||||
|
||||
app.all('/post(/*)?', basicAuth(function(user, pass){
|
||||
return 'admin' == user && 'express' == pass;
|
||||
}));
|
||||
|
||||
/**
|
||||
* Map :post to the database, loading
|
||||
* every time :post is present.
|
||||
*/
|
||||
|
||||
app.param('post', function(req, res, next, id){
|
||||
Post.get(id, function(err, post){
|
||||
if (err) return next(err);
|
||||
if (!post) return next(new Error('failed to load post ' + id));
|
||||
req.post = post;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a post.
|
||||
*/
|
||||
|
||||
app.get('/post/add', function(req, res){
|
||||
res.render('post/form', { post: {}});
|
||||
});
|
||||
|
||||
/**
|
||||
* Save a post.
|
||||
*/
|
||||
|
||||
app.post('/post', function(req, res){
|
||||
var data = req.body.post
|
||||
, post = new Post(data.title, data.body);
|
||||
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.flash('error', err.message);
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
post.save(function(err){
|
||||
req.flash('info', 'Successfully created post _%s_', post.title);
|
||||
res.redirect('/post/' + post.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Display the post.
|
||||
*/
|
||||
|
||||
app.get('/post/:post', function(req, res){
|
||||
res.render('post', { post: req.post });
|
||||
});
|
||||
|
||||
/**
|
||||
* Display the post edit form.
|
||||
*/
|
||||
|
||||
app.get('/post/:post/edit', function(req, res){
|
||||
res.render('post/form', { post: req.post });
|
||||
});
|
||||
|
||||
/**
|
||||
* Update post. Typically a data layer would handle this stuff.
|
||||
*/
|
||||
|
||||
app.put('/post/:post', function(req, res, next){
|
||||
var post = req.post;
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.flash('error', err.message);
|
||||
return res.redirect('back');
|
||||
}
|
||||
post.update(req.body.post, function(err){
|
||||
if (err) return next(err);
|
||||
req.flash('info', 'Successfully updated post');
|
||||
res.redirect('back');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
19
examples/blog/routes/site.js
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Post = require('../models/post');
|
||||
|
||||
module.exports = function(app){
|
||||
app.get('/', function(req, res){
|
||||
Post.count(function(err, count){
|
||||
Post.all(function(err, posts){
|
||||
res.render('index', {
|
||||
count: count
|
||||
, posts: posts
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
19
examples/blog/views/index.jade
Normal file
@@ -0,0 +1,19 @@
|
||||
h1 Blog
|
||||
|
||||
!= messages()
|
||||
|
||||
- if (count)
|
||||
p Display all #{count} post(s)
|
||||
#posts!= partial('post', posts)
|
||||
- else
|
||||
p
|
||||
| It looks like you have no posts!
|
||||
p
|
||||
| Click
|
||||
a(href=base + '/post/add') here
|
||||
| to create a post. Login
|
||||
| as
|
||||
em "admin"
|
||||
| and
|
||||
em "express"
|
||||
| .
|
||||
7
examples/blog/views/layout.jade
Normal file
@@ -0,0 +1,7 @@
|
||||
!!! 5
|
||||
html
|
||||
head
|
||||
title Blog
|
||||
link(rel='stylesheet', href=base + '/style.css')
|
||||
body
|
||||
#container!= body
|
||||
20
examples/blog/views/post/form.jade
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
- if (post.title)
|
||||
h1 Editing #{post.title}
|
||||
- else
|
||||
h1 New Post
|
||||
|
||||
!= messages()
|
||||
|
||||
form#post(action=base + '/post' + (post.title ? '/' + post.id : ''), method='post')
|
||||
- if (post.title)
|
||||
input(type='hidden', name='_method', value='put')
|
||||
p
|
||||
label(for='post[title]') Title:
|
||||
input(type='text', name='post[title]', value=post.title)
|
||||
p
|
||||
label(for='post[body]') Body:
|
||||
textarea(name='post[body]')= post.body || ''
|
||||
p
|
||||
input(type='submit', value=post.title ? 'Update' : 'Create')
|
||||
|
||||
16
examples/blog/views/post/index.jade
Normal file
@@ -0,0 +1,16 @@
|
||||
.post
|
||||
// title
|
||||
h2
|
||||
= post.title
|
||||
a.edit(href=base + '/post/' + post.id + '/edit') Edit
|
||||
|
||||
// flash messages
|
||||
!= messages()
|
||||
|
||||
// dates
|
||||
p.date.created Created at #{post.createdAt}
|
||||
- if (post.updatedAt)
|
||||
p.date.updated Updated at #{post.updatedAt}
|
||||
|
||||
// body
|
||||
pre.body= post.body
|
||||
47
examples/content-negotiation/app.js
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
var users = [
|
||||
{ name: 'tobi' }
|
||||
, { name: 'loki' }
|
||||
, { name: 'jane' }
|
||||
];
|
||||
|
||||
function provides(type) {
|
||||
return function(req, res, next){
|
||||
if (req.accepts(type)) return next();
|
||||
next('route');
|
||||
}
|
||||
}
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: application/json"
|
||||
|
||||
app.get('/users', provides('json'), function(req, res){
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: text/html"
|
||||
|
||||
app.get('/users', provides('html'), function(req, res){
|
||||
res.send('<ul>' + users.map(function(user){
|
||||
return '<li>' + user.name + '</li>';
|
||||
}).join('\n') + '</ul>');
|
||||
});
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: text/plain"
|
||||
|
||||
app.get('/users', function(req, res, next){
|
||||
res.contentType('txt');
|
||||
res.send(users.map(function(user){
|
||||
return user.name;
|
||||
}).join(', '));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
@@ -1,9 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
var users = [];
|
||||
|
||||
users.push({ name: 'Tobi' });
|
||||
users.push({ name: 'Loki' });
|
||||
users.push({ name: 'Jane' });
|
||||
|
||||
module.exports = users;
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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');
|
||||
}
|
||||
45
examples/cookies/app.js
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
/**
|
||||
* 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[36m:method\x1b[0m \x1b[90m:url\x1b[0m :response-time' }),
|
||||
|
||||
// Provides req.cookies
|
||||
express.cookieParser(),
|
||||
|
||||
// Parses x-www-form-urlencoded request bodies (and json)
|
||||
express.bodyParser()
|
||||
);
|
||||
|
||||
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){
|
||||
var minute = 60000;
|
||||
if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
|
||||
res.redirect('back');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
@@ -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');
|
||||
}
|
||||
51
examples/downloads/app.js
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
/**
|
||||
* 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>');
|
||||
});
|
||||
|
||||
// /files/* is accessed via req.params[0]
|
||||
// but here we name it :file
|
||||
app.get('/files/:file(*)', function(req, res, next){
|
||||
var file = req.params.file
|
||||
, path = __dirname + '/files/' + file;
|
||||
// either res.download(path) and let
|
||||
// express handle failures, or provide
|
||||
// a callback as shown below
|
||||
res.download(path, function(err){
|
||||
// if an error occurs in this callback
|
||||
// the file most likely does not exist,
|
||||
// and it's safe to respond or next(err)
|
||||
if (err) return next(err);
|
||||
|
||||
// the file has been transferred, do not respond
|
||||
// from here, though you may use this callback
|
||||
// for stats etc.
|
||||
console.log('transferred %s', path);
|
||||
}, function(err){
|
||||
// this second optional callback is used when
|
||||
// an error occurs during transmission
|
||||
});
|
||||
});
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if ('ENOENT' == err.code) {
|
||||
res.send('Cant find that file, sorry!');
|
||||
} else {
|
||||
// Not a 404
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
@@ -1,2 +0,0 @@
|
||||
Only for test.
|
||||
The file name is faked.
|
||||
@@ -1,3 +0,0 @@
|
||||
* milk
|
||||
* eggs
|
||||
* bread
|
||||
@@ -1,40 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('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');
|
||||
}
|
||||
31
examples/ejs/app.js
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Register ejs as .html
|
||||
|
||||
app.register('.html', require('ejs'));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// 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', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,57 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('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');
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
body {
|
||||
padding: 50px 80px;
|
||||
font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
6
examples/ejs/views/layout.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +0,0 @@
|
||||
<%- include('header.html') -%>
|
||||
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<% users.forEach(function(user){ %>
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
<%- include('footer.html') -%>
|
||||
3
examples/ejs/views/users/index.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
1
examples/ejs/views/users/user.html
Normal file
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
83
examples/error-pages/app.js
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// 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('":method :url" :status'));
|
||||
|
||||
// "app.router" positions our routes
|
||||
// specifically above the middleware
|
||||
// assigned below
|
||||
|
||||
app.use(app.router);
|
||||
|
||||
// Since this is the last non-error-handling
|
||||
// middleware use()d, we assume 404, as nothing else
|
||||
// responded.
|
||||
|
||||
app.use(function(req, res, next){
|
||||
// the status option, or res.statusCode = 404
|
||||
// are equivalent, however with the option we
|
||||
// get the "status" local available as well
|
||||
res.render('404', { status: 404, url: req.url });
|
||||
});
|
||||
|
||||
// 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.render('500', {
|
||||
status: err.status || 500
|
||||
, error: err
|
||||
});
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,103 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('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');
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<%- include('error_header') -%>
|
||||
<h2>Cannot find <%= url %></h2>
|
||||
<%- include('footer') -%>
|
||||
1
examples/error-pages/views/404.jade
Normal file
@@ -0,0 +1 @@
|
||||
h2 Cannot find #{url}
|
||||
@@ -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') -%>
|
||||
2
examples/error-pages/views/500.jade
Normal file
@@ -0,0 +1,2 @@
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
@@ -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>
|
||||