mirror of
https://github.com/microsoft/TypeScript-Node-Starter.git
synced 2025-11-08 14:47:28 +00:00
Merge pull request #92 from Microsoft/addAzure
Add Azure publish support
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -13,9 +13,12 @@ logs
|
||||
results
|
||||
tmp
|
||||
|
||||
#Build
|
||||
# Build
|
||||
public/css/main.css
|
||||
|
||||
# Coverage reports
|
||||
coverage
|
||||
|
||||
# API keys and secrets
|
||||
.env
|
||||
|
||||
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -3,13 +3,16 @@
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/bower_components": true,
|
||||
"**/dist": true
|
||||
"**/dist": true,
|
||||
"**/coverge": true
|
||||
},
|
||||
"typescript.referencesCodeLens.enabled": true,
|
||||
"tslint.ignoreDefinitionFiles": false,
|
||||
"tslint.autoFixOnSave": true,
|
||||
"tslint.exclude": "**/node_modules/**/*",
|
||||
"cSpell.words": [
|
||||
"definitelytyped"
|
||||
"csrf",
|
||||
"definitelytyped",
|
||||
"promisified"
|
||||
]
|
||||
}
|
||||
170
README.md
170
README.md
@@ -2,7 +2,16 @@
|
||||
|
||||
[](https://david-dm.org/Microsoft/TypeScript-Node-Starter) [](https://travis-ci.org/Microsoft/TypeScript-Node-Starter)
|
||||
|
||||
**Live Demo**: [https://typescript-node-starter.azurewebsites.net/](https://typescript-node-starter.azurewebsites.net/)
|
||||
|
||||

|
||||
|
||||
The main purpose of this repository is to show a good end-to-end project setup and workflow for writing Node code in TypeScript.
|
||||
I will try to keep this as up-to-date as possible, but community contributions and recommendations for improvements are encouraged and will be most welcome.
|
||||
|
||||
|
||||
# Pre-reqs
|
||||
To build and run this app locally you will need a few things:
|
||||
- Install [Node.js](https://nodejs.org/en/)
|
||||
- Install [MongoDB](https://docs.mongodb.com/manual/installation/)
|
||||
- Install [VS Code](https://code.visualstudio.com/)
|
||||
@@ -33,17 +42,108 @@ mongod
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
Navigate to `http://localhost:3000`
|
||||
|
||||
# TypeScript + Node
|
||||
The main purpose of this repository is to show a good end-to-end project setup and workflow for writing Node code in TypeScript.
|
||||
I will try to keep this as up-to-date as possible, but community contributions and recommendations for improvements are encouraged and will be most welcome.
|
||||
|
||||
In the next few sections I will call out everything that changes when adding TypeScript to an Express project.
|
||||
Note that all of this has already been setup for this project, but feel free to use this as a reference for converting other Node.js project to TypeScript.
|
||||
Or, if you're using VS Code, you can use `cmd + shift + b` to run the default build task (which is mapped to `npm run build`), and then you can use the command palette (`cmd + shift + p`) and select `Tasks: Run Task` > `npm: start` to run `npm start` for you.
|
||||
|
||||
> **Note on editors!** - TypeScript has great support in [every editor](http://www.typescriptlang.org/index.html#download-links), but this project has been pre-configured for use with [VS Code](https://code.visualstudio.com/).
|
||||
Throughout the README I'll try to call out specific places where VS code really shines or where this project has been setup to take advantage of specific features.
|
||||
Throughout the README I'll try to call out specific places where VS Code really shines or where this project has been setup to take advantage of specific features.
|
||||
|
||||
Finally, navigate to `http://localhost:3000` and you should see the template being served and rendered locally!
|
||||
|
||||
# Deploying the app
|
||||
There are many ways to deploy an Node app, and in general, nothing about the deployment process changes because you're using TypeScript.
|
||||
In this section, I'll walk you through how to deploy this app to Azure App Service using the extensions available in VS Code because I think it is the easiest and fastest way to get started, as well as the most friendly workflow from a developer's perspective.
|
||||
|
||||
## Pre-reqs
|
||||
- [**Azure account**](https://azure.microsoft.com/en-us/free/) - If you don't have one, you can sign up for free.
|
||||
The Azure free tier gives you plenty of resources to play around with including up to 10 App Service instances, which is what we will be using.
|
||||
- [**VS Code**](https://code.visualstudio.com/) - We'll be using the interface provided by VS Code to quickly deploy our app.
|
||||
- [**Azure App Service VS Code extension**](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice) - In VS Code, search for `Azure App Service` in the extension marketplace (5th button down on the far left menu bar), install the extension, and then reload VS Code.
|
||||
- **Create a cloud database** -
|
||||
For local development, running MongoDB on localhost is fine, however once we deploy we need a database with high availability.
|
||||
The easiest way to achieve this is by using a managed cloud database.
|
||||
There are many different providers, but the easiest one to get started with is [MongoLab](#mlab).
|
||||
|
||||
### <a name="mlab"></a> Create a managed MongoDB with MongoLab
|
||||
1. Navigate to [MongoLab's Website](https://mlab.com/), sign up for a free account, and then log in.
|
||||
2. In the **MongoDB Deployments** section, click the **Create New** button.
|
||||
3. Select any provider (I recommend **Microsoft Azure** as it provides an easier path to upgrading to globally distributed instances later).
|
||||
4. Select **Sandbox** to keep it free unless you know what you're doing, and hit **Continue**.
|
||||
5. Select a region (I recommend the region geographically closest to your app's users).
|
||||
6. Add a name, click **Continue** again, and finally **Submit Order**.
|
||||
7. Once your new database is created, select it from the **MongoDB Deployments** section.
|
||||
8. Create a user by selecting the **User** tab, clicking the **Add database user** button, adding a username and password, and then clicking **Create**.
|
||||
A user account is required to connect to the database, so remember these values because you will need them as part of your connection string.
|
||||
9. Copy the connection string from the top of the page, it should look like this: `mongodb://<dbuser>:<dbpassword>@ds036069.mlab.com:36069/test-asdf`
|
||||
and replace `<dbUser>` and `<dbpassword>` with the credentials you just created.
|
||||
Back in your project, open your `.env` file and update `MONGODB_URI` with your new connection string.
|
||||
> NOTE! - If you don't have an `.env` file yet, rename `.env.example` to `.env` and follow the comments to update the values in that file.
|
||||
10. **Success!**
|
||||
You can test that it works locally by updating `MONGODB_URI_LOCAL` to the same connection string you just updated in `MONGO_URI`.
|
||||
After rebuilding/serving, the app should work, but users that were previously created in local testing will not exist in the new database!
|
||||
Don't forget to return the `MONGO_URI_LOCAL` to your local test database (if you so desire).
|
||||
|
||||
|
||||
## Deploying to Azure App Service
|
||||
Deploying from VS Code can be broken into the following steps:
|
||||
1. Authenticate your Azure account in VS Code
|
||||
2. Build your app
|
||||
3. Zip deploy using the Azure App Service extension
|
||||
|
||||
### Sign in to your Azure account
|
||||
1. Open VS Code
|
||||
2. Expand the Azure App Service menu in the explorer menu
|
||||
- If you don't see this, you might not have the `Azure App Service` extension installed.
|
||||
See the pre-reqs section.
|
||||
3. Click `Sign in to Azure...`
|
||||
4. Choose `Copy & Open` from the resulting dialog
|
||||
- This will open `aka.ms/devicelogin` in a browser window.
|
||||
If it doesn't, just navigate there manually.
|
||||
5. Paste in the code that is on your clipboard.
|
||||
6. Go back to VS Code, you should now be signed in.
|
||||
You can confirm that everything worked by seeing your Azure subscription listed in the Azure App Service section of the explorer window.
|
||||
Additionally you should see the email associated with your account listed in the status bar at the bottom of VS Code.
|
||||
|
||||
### Build the app
|
||||
Building the app locally is required for before a zip deploy because the App Service won't execute build tasks.
|
||||
Build the app however you normally would:
|
||||
- `ctrl + shift + b` - kicks off default build in VS Code
|
||||
- execute `npm run build` from a terminal window
|
||||
|
||||
### Zip deploy from VS Code
|
||||
1. Make sure your app is built, whatever is currently in your `dist` and `node_modules` folders will be the app that is deployed.
|
||||
2. Click the blue up arrow (Deploy to Web App) on the Azure App Service section of the explorer window.
|
||||
3. Choose the entire project directory.
|
||||
If you haven't changed the name, this will be `TypeScript-Node-Starter`.
|
||||
4. Choose the subscription you want this app to be billed to (don't worry, it will be free).
|
||||
5. Choose `Create New Web App`
|
||||
6. Enter a globally unique name -
|
||||
This will be part of the URL that azure generates so it has to be unique, but if you're planning on adding a custom domain later, it's not that important. I usually just add random numbers to the end of the app name, ie. typescript-node-starter-15121214.
|
||||
7. Choose a resource group -
|
||||
If you don't know what this is, just create a new one.
|
||||
If you have lots of cloud resources that should be logically grouped together (think an app service and a database that supports that app) then you would want to put them in the same resource group.
|
||||
This can always be updated later though.
|
||||
If you create a new resource group, you'll also be prompted to pick a location for that group.
|
||||
Pick something geographically close to where your users are.
|
||||
8. Choose `Create new App Service Plan` -
|
||||
An app service plan mainly is what determines the size and cost of the hardware your app will run on, but it also manages some other settings which we can ignore for now.
|
||||
9. Choose `B1 - Basic` - This one is free.
|
||||
If you know what you're doing, feel free to select a stronger pricing tier.
|
||||
10. Choose your target node runtime version - We are deploying to Linux machines, and in addition we can choose the exact node runtime we want.
|
||||
If you don't know what you want, choose whatever the current LTS build is.
|
||||
11. Grab a cup of coffee - You'll see everything you just selected getting created in the output window.
|
||||
All of this is powered by the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/overview?view=azure-cli-latest) and can be easily replicated if you decide you want to customize this process.
|
||||
This deployment is not the fastest option (but it is the easiest!). We are literally bundling everything in your project (including the massive node_modules folder) and uploading it to our Azure app service. Times will vary, but as a baseline, my deployment took roughly 6 minutes.
|
||||
12. Add `NODE_ENV` environment variable - In the App Service section of the explorer window, expand the newly created service, right click on **Application Settings**, select **Add New Settings...**, and add `NODE_ENV` as the key and `production` as the value.
|
||||
This setting determines which database to point to.
|
||||
If you haven't created a cloud database yet, see [the setup instructions](#mlab).
|
||||
13. Profit! If everything worked you should see a page that looks like this: [TypeScript Node Starter Demo Site](https://typescript-node-starter.azurewebsites.net/)
|
||||
|
||||
### Troubleshooting failed deployments
|
||||
Deployment can fail for various reasons, if you get stuck with a page that says *Service Unavailable* or some other error, [open an issue](https://github.com/Microsoft/TypeScript-Node-Starter/issues/new) and I'll try to help you resolve the problems.
|
||||
|
||||
# TypeScript + Node
|
||||
In the next few sections I will call out everything that changes when adding TypeScript to an Express project.
|
||||
Note that all of this has already been setup for this project, but feel free to use this as a reference for converting other Node.js project to TypeScript.
|
||||
|
||||
## Getting TypeScript
|
||||
TypeScript itself is simple to add to any project with `npm`.
|
||||
@@ -99,6 +199,7 @@ Let's dissect this project's `tsconfig.json`, starting with the `compilerOptions
|
||||
```json
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"target": "es6",
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
@@ -116,12 +217,13 @@ Let's dissect this project's `tsconfig.json`, starting with the `compilerOptions
|
||||
|
||||
| `compilerOptions` | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `"module": "commonjs"` | The **output** module type (in your `.js` files). Node uses commonjs, so that is what we use |
|
||||
| `"module": "commonjs"` | The **output** module type (in your `.js` files). Node uses commonjs, so that is what we use |
|
||||
| `"esModuleInterop": true,` | Allows usage of an alternate module import syntax: `import foo from 'foo';` |
|
||||
| `"target": "es6"` | The output language level. Node supports ES6, so we can target that here |
|
||||
| `"noImplicitAny": true` | Enables a stricter setting which throws errors when something has a default `any` value |
|
||||
| `"moduleResolution": "node"` | TypeScript attempts to mimic Node's module resolution strategy. Read more [here](https://www.typescriptlang.org/docs/handbook/module-resolution.html#node) |
|
||||
| `"sourceMap": true` | We want source maps to be output along side our JavaScript. See the [debugging](#debugging) section |
|
||||
| `"outDir": "dist"` | Location to output `.js` files after compilation |
|
||||
| `"sourceMap": true` | We want source maps to be output along side our JavaScript. See the [debugging](#debugging) section |
|
||||
| `"outDir": "dist"` | Location to output `.js` files after compilation |
|
||||
| `"baseUrl": "."` | Part of configuring module resolution. See [path mapping section](#installing-dts-files-from-definitelytyped) |
|
||||
| `paths: {...}` | Part of configuring module resolution. See [path mapping section](#installing-dts-files-from-definitelytyped) |
|
||||
|
||||
@@ -153,17 +255,21 @@ Below is a list of all the scripts this template has available:
|
||||
|
||||
| Npm Script | Description |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
|
||||
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
|
||||
| `build` | Full build. Runs ALL build tasks (`build-sass`, `build-ts`, `tslint`, `copy-static-assets`) |
|
||||
| `serve` | Runs node on `dist/server.js` which is the apps entry point |
|
||||
| `watch-node` | Runs node with nodemon so the process restarts if it crashes. Used in the main watch task |
|
||||
| `watch` | Runs all watch tasks (TypeScript, Sass, Node). Use this if you're not touching static assets. |
|
||||
| `test` | Runs tests using Jest test runner |
|
||||
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
|
||||
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
|
||||
| `watch-ts` | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed |
|
||||
| `build-sass` | Compiles all `.scss` files to `.css` files |
|
||||
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
|
||||
| `tslint` | Runs TSLint on project files |
|
||||
| `build-sass` | Compiles all `.scss` files to `.css` files |
|
||||
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
|
||||
| `tslint` | Runs TSLint on project files |
|
||||
| `copy-static-assets` | Calls script that copies JS libs, fonts, and images to dist directory |
|
||||
| `debug` | Performs a full build and then serves the app in watch mode |
|
||||
| `serve-debug` | Runs the app with the --inspect flag |
|
||||
| `watch-debug` | The same as `watch` but includes the --inspect flag so you can attach a debugger |
|
||||
|
||||
## Type Definition (`.d.ts`) Files
|
||||
TypeScript uses `.d.ts` files to provide types for JavaScript libraries that were not written in TypeScript.
|
||||
@@ -334,7 +440,8 @@ This preprocess step is very flexible, but in our case, we just want to compile
|
||||
This all happens in memory when you run the tests, so there are no output `.js` test files for you to manage.
|
||||
|
||||
### Running tests
|
||||
|
||||
Simply run `npm run test`.
|
||||
Note this will also generate a coverage report.
|
||||
|
||||
### Writing tests
|
||||
Writing tests for web apps has entire books dedicated to it and best practices are strongly influenced by personal style, so I'm deliberately avoiding discussing how or when to write tests in this guide.
|
||||
@@ -370,6 +477,7 @@ To enhance your development experience while working in VSCode we also provide y
|
||||
- [TSLint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint)
|
||||
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)
|
||||
- [Azure Cosmos DB](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-cosmosdb)
|
||||
- [Azure App Service](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice)
|
||||
|
||||
# Dependencies
|
||||
Dependencies are managed through `package.json`.
|
||||
@@ -378,44 +486,48 @@ In that file you'll find two sections:
|
||||
|
||||
| Package | Description |
|
||||
| ------------------------------- | --------------------------------------------------------------------- |
|
||||
| async | Utility library that provides asynchronous control flow. |
|
||||
| async | Utility library that provides asynchronous control flow. |
|
||||
| bcrypt-nodejs | Library for hashing and salting user passwords. |
|
||||
| bluebird | Promise library |
|
||||
| body-parser | Express 4 middleware. |
|
||||
| compression | Express 4 middleware. |
|
||||
| connect-mongo | MongoDB session store for Express. |
|
||||
| dotenv | Loads environment variables from .env file. |
|
||||
| dotenv | Loads environment variables from .env file. |
|
||||
| errorhandler | Express 4 middleware. |
|
||||
| express | Node.js web framework. |
|
||||
| express-flash | Provides flash messages for Express. |
|
||||
| express-flash | Provides flash messages for Express. |
|
||||
| express-session | Express 4 middleware. |
|
||||
| express-validator | Easy form validation for Express. |
|
||||
| fbgraph | Facebook Graph API library. |
|
||||
| lodash | General utility library. |
|
||||
| lusca | CSRF middleware. |
|
||||
| mongoose | MongoDB ODM. |
|
||||
| morgan | Express 4 middleware. |
|
||||
| nodemailer | Node.js library for sending emails. |
|
||||
| passport | Simple and elegant authentication library for node.js |
|
||||
| passport-facebook | Sign-in with Facebook plugin. |
|
||||
| passport-local | Sign-in with Username and Password plugin. |
|
||||
| pug (jade) | Template engine for Express. |
|
||||
| request | Simplified HTTP request library. |
|
||||
| pug (jade) | Template engine for Express. |
|
||||
| request | Simplified HTTP request library. |
|
||||
| request-promise | Promisified HTTP request library. Let's us use async/await |
|
||||
| winston | Logging library |
|
||||
|
||||
## `devDependencies`
|
||||
|
||||
| Package | Description |
|
||||
| ------------------------------- | --------------------------------------------------------------------- |
|
||||
| @types | Dependencies in this folder are `.d.ts` files used to provide types |
|
||||
| chai | Testing utility library that makes it easier to write tests |
|
||||
| concurrently | Utility that manages multiple concurrent tasks. Used with npm scripts |
|
||||
| jest | Testing library for JavaScript. |
|
||||
| node-sass | Allows to compile .scss files to .css |
|
||||
| node-sass | Allows to compile .scss files to .css |
|
||||
| nodemon | Utility that automatically restarts node process when it crashes |
|
||||
| supertest | HTTP assertion library. |
|
||||
| ts-test | A preprocessor with sourcemap support to help use TypeScript wit Jest.|
|
||||
| tslint | Linter (similar to ESLint) for TypeScript files |
|
||||
| ts-node | Enables directly running TS files. Used to run `copy-static-assets.ts` |
|
||||
| tslint | Linter (similar to ESLint) for TypeScript files |
|
||||
| typescript | JavaScript compiler/type checker that boosts JavaScript productivity |
|
||||
|
||||
To install or update these dependencies you can use `npm install` or `npm update`.
|
||||
|
||||
# Other
|
||||
Here is a section of miscellaneous tips.
|
||||
|
||||
# Hackathon Starter Project
|
||||
A majority of this quick start's content was inspired or adapted from Sahat's excellent [Hackathon Starter project](https://github.com/sahat/hackathon-starter).
|
||||
|
||||
98
package-lock.json
generated
98
package-lock.json
generated
@@ -91,7 +91,7 @@
|
||||
"@types/bson": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-1.0.6.tgz",
|
||||
"integrity": "sha512-v7N8qcTGiYhLRyi+Y69R3tPC4GLqByCg3NC2EO6PciC166O9dNhjFPoXeMePtZ+0f+/O2xLDWXs5BLnRfcBaBA==",
|
||||
"integrity": "sha1-hpHwQtmd0WOl603W3eWH00SffNo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "9.4.6"
|
||||
@@ -193,7 +193,7 @@
|
||||
"@types/form-data": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
|
||||
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
|
||||
"integrity": "sha1-7is7jqoRwJOCiZU2BrdFtzjFSx4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "9.4.6"
|
||||
@@ -368,7 +368,7 @@
|
||||
"@types/superagent": {
|
||||
"version": "3.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.5.6.tgz",
|
||||
"integrity": "sha1-nPJjLAdbqeYB9qYQqtwjmS0COUw=",
|
||||
"integrity": "sha512-yGiVkRbB1qtIkRCpEJIxlHazBoILmu33xbbu4IiwxTJjwDi/EudiPYAD7QwWe035jkE40yQgTVXZsAePFtleww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "9.4.6"
|
||||
@@ -389,6 +389,15 @@
|
||||
"integrity": "sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/winston": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.3.8.tgz",
|
||||
"integrity": "sha512-QqR0j08RCS1AQYPMRPHikEpcmK+2aEEbcSzWLwOqyJ4FhLmHUx/WjRrnn7tTQg/y4IKnMhzskh/o7qvGIZZ7iA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "9.4.6"
|
||||
}
|
||||
},
|
||||
"abab": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||
@@ -398,7 +407,7 @@
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"accepts": {
|
||||
@@ -505,7 +514,7 @@
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
"integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
@@ -1329,6 +1338,11 @@
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
|
||||
@@ -1406,7 +1420,7 @@
|
||||
"configstore": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.1.tgz",
|
||||
"integrity": "sha1-CU7mYquD+tmRdnjeEU+q6o/NypA=",
|
||||
"integrity": "sha512-5oNkD/L++l0O6xGXxb1EWS7SivtjfGQlRyxJsYgE0Z495/L81e2h4/d3r969hoPXuFItzNOKMtsXgYG4c7dYvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dot-prop": "4.2.0",
|
||||
@@ -1586,6 +1600,11 @@
|
||||
"array-find-index": "1.0.2"
|
||||
}
|
||||
},
|
||||
"cycle": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
|
||||
"integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
@@ -1597,7 +1616,7 @@
|
||||
"date-fns": {
|
||||
"version": "1.29.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz",
|
||||
"integrity": "sha1-EuYJzcuTUScxHQTTMzTilgoqVOY=",
|
||||
"integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
@@ -1712,7 +1731,7 @@
|
||||
"dot-prop": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
|
||||
"integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=",
|
||||
"integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-obj": "1.0.1"
|
||||
@@ -2065,6 +2084,11 @@
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"eyes": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
|
||||
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
|
||||
@@ -2232,7 +2256,7 @@
|
||||
"fs-extra": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||
"integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
@@ -5224,7 +5248,7 @@
|
||||
"make-dir": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz",
|
||||
"integrity": "sha1-GbQ2n+SMEW9Twq+VrRAsDjnoXVE=",
|
||||
"integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "3.0.0"
|
||||
@@ -5882,7 +5906,7 @@
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
|
||||
"integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=",
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"are-we-there-yet": "1.1.4",
|
||||
@@ -6760,11 +6784,21 @@
|
||||
"uuid": "3.1.0"
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
|
||||
"requires": {
|
||||
"bluebird": "3.5.1",
|
||||
"request-promise-core": "1.1.1",
|
||||
"stealthy-require": "1.1.1",
|
||||
"tough-cookie": "2.3.3"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
|
||||
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "4.17.4"
|
||||
}
|
||||
@@ -7221,6 +7255,11 @@
|
||||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
|
||||
},
|
||||
"stack-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
@@ -7244,8 +7283,7 @@
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
|
||||
"dev": true
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"stream-combiner": {
|
||||
"version": "0.0.4",
|
||||
@@ -7510,7 +7548,7 @@
|
||||
"touch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
||||
"integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=",
|
||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nopt": "1.0.10"
|
||||
@@ -7555,7 +7593,7 @@
|
||||
"tree-kill": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz",
|
||||
"integrity": "sha1-WEZ4Yje0I5AU8F2xVrZDIS1MbzY=",
|
||||
"integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==",
|
||||
"dev": true
|
||||
},
|
||||
"trim-newlines": {
|
||||
@@ -7955,7 +7993,7 @@
|
||||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
@@ -7964,7 +8002,7 @@
|
||||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
@@ -8036,7 +8074,7 @@
|
||||
"validator": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz",
|
||||
"integrity": "sha1-PBI3KQ43CSNVNE/veMIxJJ2rd7k="
|
||||
"integrity": "sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
@@ -8138,7 +8176,7 @@
|
||||
"wide-align": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
|
||||
"integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=",
|
||||
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "1.0.2"
|
||||
@@ -8186,6 +8224,26 @@
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
|
||||
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
|
||||
},
|
||||
"winston": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz",
|
||||
"integrity": "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4=",
|
||||
"requires": {
|
||||
"async": "1.0.0",
|
||||
"colors": "1.0.3",
|
||||
"cycle": "1.0.3",
|
||||
"eyes": "0.1.8",
|
||||
"isstream": "0.1.2",
|
||||
"stack-trace": "0.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
||||
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
|
||||
}
|
||||
}
|
||||
},
|
||||
"with": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz",
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
"lodash": "^4.17.4",
|
||||
"lusca": "^1.5.2",
|
||||
"mongoose": "^4.13.11",
|
||||
"morgan": "^1.9.0",
|
||||
"nodemailer": "^4.4.1",
|
||||
"passport": "^0.4.0",
|
||||
"passport-facebook": "^2.1.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pug": "^2.0.0-rc.4",
|
||||
"request": "^2.83.0"
|
||||
"request": "^2.83.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"winston": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/async": "^2.0.45",
|
||||
@@ -76,6 +77,7 @@
|
||||
"@types/request": "^2.47.0",
|
||||
"@types/shelljs": "^0.7.8",
|
||||
"@types/supertest": "^2.0.4",
|
||||
"@types/winston": "^2.3.7",
|
||||
"chai": "^4.1.2",
|
||||
"concurrently": "^3.5.1",
|
||||
"jest": "^22.0.4",
|
||||
|
||||
@@ -2,7 +2,7 @@ import express from "express";
|
||||
import compression from "compression"; // compresses requests
|
||||
import session from "express-session";
|
||||
import bodyParser from "body-parser";
|
||||
import logger from "morgan";
|
||||
import logger from "./util/logger";
|
||||
import lusca from "lusca";
|
||||
import dotenv from "dotenv";
|
||||
import mongo from "connect-mongo";
|
||||
@@ -12,6 +12,7 @@ import mongoose from "mongoose";
|
||||
import passport from "passport";
|
||||
import expressValidator from "express-validator";
|
||||
import bluebird from "bluebird";
|
||||
import { MONGODB_URI, SESSION_SECRET } from "./util/secrets";
|
||||
|
||||
const MongoStore = mongo(session);
|
||||
|
||||
@@ -32,7 +33,7 @@ import * as passportConfig from "./config/passport";
|
||||
const app = express();
|
||||
|
||||
// Connect to MongoDB
|
||||
const mongoUrl = process.env.MONGOLAB_URI;
|
||||
const mongoUrl = MONGODB_URI;
|
||||
(<any>mongoose).Promise = bluebird;
|
||||
mongoose.connect(mongoUrl, {useMongoClient: true}).then(
|
||||
() => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ },
|
||||
@@ -46,14 +47,13 @@ app.set("port", process.env.PORT || 3000);
|
||||
app.set("views", path.join(__dirname, "../views"));
|
||||
app.set("view engine", "pug");
|
||||
app.use(compression());
|
||||
app.use(logger("dev"));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(expressValidator());
|
||||
app.use(session({
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
secret: process.env.SESSION_SECRET,
|
||||
secret: SESSION_SECRET,
|
||||
store: new MongoStore({
|
||||
url: mongoUrl,
|
||||
autoReconnect: true
|
||||
|
||||
17
src/util/logger.ts
Normal file
17
src/util/logger.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import winston from "winston";
|
||||
import { Logger } from "winston";
|
||||
import { ENVIRONMENT } from "./secrets";
|
||||
|
||||
const logger = new (Logger)({
|
||||
transports: [
|
||||
new (winston.transports.Console)({ level: process.env.NODE_ENV === "production" ? "error" : "debug" }),
|
||||
new (winston.transports.File)({ filename: "debug.log", level: "debug"})
|
||||
]
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
logger.debug("Logging initialized at debug level");
|
||||
}
|
||||
|
||||
export default logger;
|
||||
|
||||
26
src/util/secrets.ts
Normal file
26
src/util/secrets.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import logger from "./logger";
|
||||
import dotenv from "dotenv";
|
||||
import fs from "fs";
|
||||
|
||||
if (fs.existsSync(".env")) {
|
||||
logger.debug("Using .env file to supply config environment variables");
|
||||
dotenv.config({ path: ".env" });
|
||||
} else {
|
||||
logger.debug("Using .env.example file to supply config environment variables");
|
||||
dotenv.config({ path: ".env.example" }); // you can delete this after you create your own .env file!
|
||||
}
|
||||
export const ENVIRONMENT = process.env.NODE_ENV;
|
||||
const prod = ENVIRONMENT === "production"; // Anything else is treated as 'dev'
|
||||
|
||||
export const SESSION_SECRET = process.env["SESSION_SECRET"];
|
||||
export const MONGODB_URI = prod ? process.env["MONGODB_URI"] : process.env["MONGODB_URI_LOCAL"];
|
||||
|
||||
if (!SESSION_SECRET) {
|
||||
logger.error("No client secret. Set SESSION_SECRET environment variable.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!MONGODB_URI) {
|
||||
logger.error("No mongo connection string. Set MONGODB_URI environment variable.");
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -22,6 +22,7 @@ html(lang='')
|
||||
|
||||
script(src='/js/lib/jquery-3.1.1.min.js')
|
||||
script(src='/js/lib/bootstrap.min.js')
|
||||
script(async defer src="https://buttons.github.io/buttons.js")
|
||||
script(src='/js/main.js')
|
||||
|
||||
//- Google Analytics: change UA-XXXXX-X to be your site's ID
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
footer
|
||||
.container.text-center
|
||||
p.pull-left © 2018 Company, Inc. All Rights Reserved
|
||||
iframe.pull-right(src="https://ghbtns.com/github-btn.html?user=Microsoft&repo=TypeScript-Node-Starter&type=star&count=true" width="90" height="20" style="margin-top:15px; border: 0; overflow: hidden;")
|
||||
a.github-button.pull-right(href="https://github.com/microsoft/typescript-node-starter", data-icon="octicon-star", data-show-count="true", aria-label="Star microsoft/typescript-node-starter on GitHub") Star
|
||||
|
||||
Reference in New Issue
Block a user