首页 > 代码库 > MEANJS DOC
MEANJS DOC
Overview
Thank you for downloading the MEAN.JS boilerplate!
This simple documentation will cover the basics of developing your MEAN application.
Before you begin we recommend you read about the basic building blocks that assemble a MEAN.JS application:
- MongoDB
- Go through MongoDB Official Website and proceed to its Great Manual, which should help you understand NoSQL and MongoDB better.
- Express
- The best way to understand express is through its Official Website, particularly The Express Guide; you can also go through this StackOverflow Thread for more resources.
- AngularJS
- Angular‘s Official Website is a great starting point. You can also use Thinkster Popular Guide, and the Egghead Videos.
- Node.js
- Start by going through Node.js Official Website and this StackOverflow Thread, which should get you going with the Node.js platform in no time.
When you‘re done with those resources and feel you understand the basic principals continue to other sections.
Enjoy & keep us updated,
The MEAN.JS Team.
Getting Started
In this section you‘ll learn how to get started with a MEAN.JS application, install all the prerequisites, and initialize your application.
Prerequisites
Before you begin, you should make sure you have installed all these prerequisites on your development machine.
- Node.js & npm
- Download & Install Node.js and the npm package manager, if you encounter any problems, you can also use this Github Gist to install Node.js.
- MongoDB
- Download & Install MongoDB, and make sure it‘s running on the default port (27017).
- Bower
- You‘re going to use the Bower Package Manager to manage your front-end packages, in order to install it make sure you‘ve installed Node.js and npm, then install bower globally using npm:
$ npm install -g bower
- Grunt
- You‘re going to use the Grunt Task Runner to automate your development process, in order to install it make sure you‘ve installed Node.js and npm, then install grunt globally using npm:
$ npm install -g grunt-cli
Note: Your user might not have the permissions to install package globally, so use a super user or sudo.
Downloading MEAN.JS
There are several ways you can get the MEAN.JS boilerplate:
Yo Generator
The recommended way would be to use the official Yo Generator which will generate the latest stable copy of the MEAN.JS boilerplate and supply multiple sub-generators to ease your daily development cycles.
Note: If you want to support git mergeupdates it would be better to use git clonefor your initial project creation, don‘t worry you‘d still be able use the generator.
Cloning The GitHub Repository
You can also use Git to directly clone the MEAN.JS repository:
$ git clone https://github.com/meanjs/mean.git meanjs
This will clone the latest version of the MEAN.JS repository to a meanjs folder.
Downloading The Repository Zip File
Another way to use the MEAN.JS boilerplate is to download a zip copy from the master branch on github. You can also do this using wget command:
$ wget https://github.com/meanjs/mean/archive/master.zip -O meanjs.zip; unzip meanjs.zip; rm meanjs.zip
Don‘t forget to rename mean-master after your project name.
Quick Install
Once you‘ve installed all the prerequisites, you‘re just a few steps away from starting to develop you MEAN application.
The first thing you should do is install the Node.js dependencies. The boilerplate comes pre-bundled with a package.json file that contains the list of modules you need to start your application, to learn more about the modules installed visit the NPM & Package.json section.
To install Node.js dependencies you‘re going to use npm again, just run this in the command-line:
$ npm install
This command does a few things:
- First it will install the dependencies needed for the application to run.
- If you‘re running in a development environment, it will then also install development dependencies needed for testing and running your application.
- Finally, when the install process is over, npm will initiate a
bower install
command to install all the front-end modules needed for the application.
Running Your Application
After the install process is over, you‘ll be able to run your application using Grunt, just run grunt default task:
$ grunt
Your application should run on the 3000 port so in your browser just go to http://localhost:3000.
That‘s it! your application should be running by now, to proceed with your development check the other sections in this documentation.
If you encounter any problem try the Troubleshooting section.
Troubleshooting
During the installation process you may encounter some problems, so what can you do?
Check Node.js and npm Versions
The rapid advancements in JavaScript modules can sometimes cause version issues with the MEAN‘s dependencies. We try to keep up with the stable versions, and make sure the modules versions are compatible with those versions. We can‘t control the pre-installed platforms versions, so make sure you didn‘t install unsupported versions of Node.js and MongoDB.
- MongoDB
- MongoDB version 2.4.x is supported.
- Node.js
- Node version 0.10.x is supported.
- npm
- npm version 1.3.x is supported.
Update npm, Bower or Grunt
You may find there is a weird error during install like npm‘s Error: ENOENT, usually updating those tools to the latest version solves the issue.
- Updating npm
- To update npm just run this command in the command-line:
$ npm update -g npm
- Updating Bower
- To update bower just run this command in the command-line:
$ npm update -g bower
- Updating Grunt
- To update grunt just run this command in the command-line:
$ npm update -g grunt-cli
Cleaning npm and Bower cache
Both npm and Bower uses a caching system that caches the packages you already installed. Often cleaning npm & Bower‘s cache can solve some of the issues you encounter during the installation process.
- Cleaning npm‘s cache
- To clean npm‘s cache just run this command in the command-line:
$ npm cache clean
- Cleaning Bower‘s cache
- To clean bower‘s cache just run this command in the command-line:
$ bower cache clean
Common Issues
There are some common errors while installing mean:
- Node is running but AgnularJS application won‘t load
- Check to see all your front-end packages were installed. Bower package manager is used to install the front-end package and it will need a .bowerrc file to install the packages in the right location.
Bower should install the packages in the public/lib folder, so if this folder or some of its sub-folders doesn‘t exist, run:$ bower update
This will install the missing packages. - Error: failed to connect to [localhost:27017]
- If you use a local MongoDB check to see if its running. In case you use an external service verify the URI in theconfiguration files.
Sometimes it can be a local issue or something that we didn‘t cover, in case you have any further questions please contact us via the community page.
Folder Structure
The folder structure is quite self-explanatory, but here‘s an explanation on what goes where and why.
App
The server folder contains all the server files you use in your application, this is where you store your MVC server files.
controllers
The controllers folder is where you store your Express application controllers, this is where you write your backend business logic.When to use: Whenever you want to add, change, or remove Express application controllers.
models
Autoloaded
The models folder is where you store your Mongoose models, this is where you define your backend models.When to use: Whenever you want to add, change, or remove Mongoose models.
routes
Autoloaded
The routes folder contains the Server routing configuration files, this is where you define your Express routes, in order to add routes to your module just add a .js file similar to the app/routes/articles.js file and MEAN will automatically load that these routes.When to use: Whenever you want to add, change, or remove a server route.
tests
The tests folder is where you store your Mocha tests, this is how you test your backend business logic.When to use: Whenever you want to add, change, or remove Mocha tests.
views
The views folder is where define your backend views. Since you‘ll use AngularJS, server templates are almost meaningless, but you still have to use a template engine to render the main pages, like the index and error pages. For more information visit the Backend Views section.When to use: Whenever you want to add, change, or remove backend views.
templates
A backend templates folder, currently used for emails templates.When to use: Whenever you want to add, change, or remove backend templates.
Config
The config folder contains the files you need to configure your application.
env
The env folder contains the configuration files loaded by the config.js file according to the current environment, for more information, please visit the Configuration section.When to use: Whenever you want to add, change, or remove your configuration properties.
strategies
Autoloaded
The strategies folder contains the startegies configuration files loaded by the passport.js file.When to use: Whenever you want to add, change, or remove a Passport Strategy.
config.js
The configuration loader that loads the right configuration from the env folder, for more information, please visit theConfiguration section.express.js
Express configuration file, it initializes & configures the Express application.When to use: Whenever you want to change the way Express is being initialized and configured.
init.js
The initialization file that set up a few project related configuraiton.passport.js
Passport configuration file that initializes & configures the Passport‘s authentication strategies and middlewares from the strategies folder.
Public
The public folder contains all the static files you use in your application, this is where you store your front-end files.
dist
The distribution folder is where you store your application compressed CSS and JavaScript assets. The uglify and cssmingrunt tasks are using this as their build target folder.modules
Autoloaded
The modules folder is where you store AngularJS application modules, to learn more about it visit the AngularJS Modulessection.When to use: Whenever you want to add, change, or remove AngularJS modules.
config.js
AngularJS configuration module, it starts with two global properties and one method:- applicationModuleName
- AngularJS is using a module system to bootstrap and application, in this case it will use this property as the main module name.
- applicationModuleVendorDependencies
- AngularJS allows to add dependencies to the main module forcing the application not to start if those dependencies aren‘t met. In this case we start with the basic AngularJS & Angular-UI dependencies, each third-party module you add to your application should be added to the applicationModuleVendorDependencies global property and AngularJS will load it automatically.
- registerModule
- This method is used to register a module as a new module and add it to the main module dependencies.
Although you don‘t have to, it is highly recommended that you use registerModule method to reigster your module as a dependency for the main application module. To understand this better please visit the AngularJS Modules section.
When to use: Whenever you want to add, change, or remove an AngularJS global configuration property.
application.js
AngularJS main application file, it takes care of bootstrapping the application and attaching the right modules.When to use: Whenever you want to add, change, or remove a module in your AngularJS application.
Application Files
There are a few application files stored in root folder.
server.js
Our main application file, where you initialize your Node.js application.bower.json
Bower definition file, where you configure the front-end components you want to use, for more information visit theBower section.When to use: Whenever you want to add, change, or remove front-end components.
Dockerfile
Docker configuration file, where you configure all the commands you would normally execute manually in order to build a Docker image.When to use: Whenever you want to configure your Docker images.
fig.yml
Docker development environment configuration file, where you configure your application environment with Docker .gruntfile.js
Grunt definition file is where you define your grant tasks, for more information visit the Grunt section.When to use: Whenever you want to add, change, or remove grunt tasks.
karma.conf.js
Karma configuration file is where you configure your karma tests.When to use: Whenever you want to add, change, or remove front-end tests.
package.json
npm definition file, where you configure the backend modules you want to use, for more information visit the NPMsection.When to use: Whenever you want to add, change, or remove backend modules.
Procfile
Heroku process file, where you configure process you want to run on Heroku application Dyno.
Hidden Configuration Files
Notice that sometimes you copy your application folder‘s content and forget to copy the hidden files, this will cause issues and might break the application.
.bowerrc
Bower configuration file, you use it to tell bower where to install your application components..csslintrc
CSSLint configuration file, you use it to configure CSSLint special properties.When to use: Whenever you want to add, change, or remove CSSLint properties.
.editconfig
EditorConfig configuration file, you use it to configure consistent coding styles between different editors and IDEs..gitignore
Git ignore file, you use it to tell git what ignore in next commits. After installation the application generates a lot of code that you don‘t want to include in your repository, so this is where you tell git to ignore those files.When to use: Whenever you want to add, change, or remove files that are ignored by Git.
.jshintrc
JSHint configuration file, you use it to configure JSHint special properties.When to use: Whenever you want to add, change, or remove JSHint properties.
.slugignore
Heroku ignore file, you use it to tell Heroku slug compiler what ignore in next commits, which will prevent oversizing your final slug.When to use: Whenever you want to add, change, or remove files that are ignored by Heroku slug compiler.
.travis.yml
Travis configuration file, you use it to tell Travis how you want your builds to be executed.When to use: Whenever you want to add, change, or remove TravisCI configuration options.
Configuration
So, you have your application running, but how do you configure it?
Environmental Configuration
The config folder is where you have all the files are organized in a specific structure, which starts with the config.jsfile.
The config file functions as loader for the configurations files placed in the config/env folder, it will load the right configuration file based on the NODE_ENV variable.
There are five default configuration files based on common development pattern:
- config/env/all.js
- This file will be loaded in all the environments, and contains the default properties that will be overwritten by any environment specified configuration.
- config/env/development.js
- This file will be loaded in a development environment, a property defined here will overwrite the one defined in the all.js file.
- config/env/production.js
- This file will be loaded in a production environment, a property defined here will overwrite the one defined in the all.js file.
- config/env/test.js
- This file will be loaded in a test environment, a property defined here will overwrite the one defined in the all.js file.
- config/env/travis.js
- This file will be loaded in the Travis CI testing environment, a property defined here will overwrite the one defined in the all.js file.
To run your application with a different environment configuration run the application like this:
$ NODE_ENV={The Environment Name} grunt
Configuration Properties
MEAN.JS comes with a default set of configuration properties you will most likely expand with your properties. Here‘s the review of all the required properties used in the configuration files:
- config.db
- This is the MongoDB connection string URI, when bootstrapped, the application will try to connect to the database using this URI, so make sure its the correct one in each environment.
- config.port
- The port used by the application, default is 3000, but as you can notice in the test.js config file, this can be changed.
- config.app.title
- This is title used as the HTML page title. Notice that it appears both in the all.js file and in all the non-production configuration files.
- config.app.description
- This is used in the HTML description META tag. Notice that it only appears in the all.js file and can be overwritten by an environment specific property.
- config.app.keywords
- This is used in the HTML keywords META tag. Notice that it only appears in the all.js file and can be overwritten by an environment specific property.
Assets Configuration
One of the major issues dealing with applications development is assets management. While bower helps you download and update the project front-end dependencies, you would still need to include the packages JavaScript files in several places including your main application page, Karma configuration file and the uglify grunt task. Furthermore, you may want to use different assets for different environments.
For this purpose we included the config.assets field in the environments configuration files. Using this configuration option allows you to organize all your assets inclusion in a single place. The config.assets field has a few properties:
- config.assets.css
- A list of glob patterns indicating the project css files.
- config.assets.js
- A list of glob patterns idicating the project JavaScript project files.
- config.assets.tests
- A list of glob patterns idicating the project Jasmine test files.
- config.assets.lib
A list of glob patterns idicating the project packages files. We seperate those from other files so you could use CDN assets in your production configuration.
- config.assets.lib.css
- A list of glob patterns idicating the project packages CSS files.
- config.assets.lib.js
- A list of glob patterns idicating the project packages JavaScript files.
Note: You can also include CDN paths to load packages files directly from their official CDN.
Social Configuration Properties
The application will use the Passport module to offer users various login options.
MEAN.JS currently supports five social platforms: Facebook, Twitter, Google, Linkedin, and Github. You can also add other platforms using a passport-provider package and duplicating the samples logic.
To configure your social application oauth keys there‘s a property object for each platform:
- config.app.{OAuth Provider}.clientID
- Your application oauth id.
- config.app.{OAuth Provider}.clientSecret
- Your application oauth secret.
- config.app.{OAuth Provider}.callbackURL
- Your application oauth callback URL.
Remember to use different configuration for each environment especially your MongoDB URI and social platform OAuth Keys.
Nodemailer Configuration Properties
The application will use the Nodemailer module to send email notifications.
To configure nodemailer there are several properties:
- config.mailer.from
- The sender address you want to use. (Example: John Doe <johndoe@example.com>)
- config.mailer.options.service
- The Email service you would like to use. (Example: gmail)
- config.mailer.options.auth.user
- The Email service username.
- config.mailer.options.auth.password
- The Email service password.
Automatically Loaded Files
Through the system we have several object automatically loaded during the application bootstrap. This was done to ease the development process and to help avoid the common mistake of not including your newly created files. The objects that are loaded automatically are:
- app/models
- Mongoose models are registered automatically during the application bootstrap process. So you can just call themongoose.model(‘modelName‘) whenever you need.
- app/routes
- Routing files placed in this folder will be registered automatically with the Express application. So whenever you add a new routing configuration, the new routes will be immediately available.
- config/strategies
- Passport strategies placed in this folder will automatically be loaded by the config/passport.js file. So whenever you add a new strategy, it will be available instantly.
- public/modules
- The new vertical modules scheme allows us to automatically include the module files in your application HTML file, this includes both JavaScript and CSS files. So have fun creating your modules, and don‘t worry about including your files.
NPM
npm is the Node.js package manager that uses a JSON file to configure the backend modules your application will use, the modules will be stored in the node_modules folder.
General Dependencies
Here‘s the description of the default dependencies you‘ll use to bootstrap your MEAN application.
- Express
- Express is a web framework for Node.js.
- Express-Session
- Express-Session is the session middleware for Express 4.x applications.
- Body-Parser
- Body-Parser is a body parsing middleware for Express 4.x applications.
- Cookie-Parser
- Cookie-Parser is a cookie parsing middleware for Express 4.x applications.
- Compression
- Compression is a compression middleware for Express 4.x applications.
- Method-Override
- Method-Override provides faux HTTP method support for Express 4.x applications.
- Morgan
- Morgan is the connect logger module for Express 4.x applications.
- Helmet
- Helmet is a set of middlewares that implement various security headers for Express applications.
- Glob
- Glob provides glob functionality for node.js applications.
- Consolidate
- Consolidate.js is a template engine consolidation module for Node.js.
- Swig
- Swig is a template engine for Node.js.
- Mongoose
- Mongoose is a Mongodb object-modeling module for Node.js.
- Connect-mongo
- Connect-mongo is a Mongodb session store module for Node.js.
- Connect-flash
- Connect-flash is a middleware used to store and retrieve messages from the session.
- Passport
- Passport is an authentication middleware for Node.js that enables authentication from various OAuth sources like Facebook, Twitter, etc.
- Passport-Local
- Passport-Local is an authentication strategy for passport that enables users to authenticate using username and password.
- Passport-Facebook
- Passport-Facebook is an authentication strategy for passport that enables users to authenticate using their Facebook account.
- Passport-Twitter
- Passport-Twitter is an authentication strategy for passport that enables users to authenticate using their Twitter account.
- Passport-Linkedin
- Passport-Linkedin is an authentication strategy for passport that enables users to authenticate using their Linkedin account.
- Passport-Google-OAuth
- Passport-Google-OAuth is an authentication strategy for passport that enables users to authenticate using their Google account.
- Passport-Github
- Passport-Github is an authentication strategy for passport that enables users to authenticate using their Github account.
- Lodash
- Lodash is a JavaScript utility library, for manipulating collections and objects.
- Forever
- Forever is a Node.js module that enable node to run continuously. We use it for consistency when running on Heroku.
- Bower
- Bower is a package manager for front-end components.
- Grunt
- Grunt is a JavaScript task runner.
- Grunt-CLI
- Grunt-CLI is Grunt‘s command line interface.
- nodemailer
- Nodemailer is an email sending module.
Development Dependencies
Here‘s the description of the development dependencies you‘ll use to test and run your MEAN application.
- Supertest
- Supertest is a library for testing Node.js HTTP API.
- Should
- Should is an assertion library for BDD testing.
- Grunt-Node-Inspector
- Grunt-Node-Inspector is grunt task that that runs the node-inspector debugging tool for Node.js applications.
- Grunt-Contrib-Watch
- Grunt-Contrib-Watch is a grunt task that runs tasks whenever watched file change.
- Grunt-Contrib-JSHint
- Grunt-Contrib-JSHint is a grunt task that lint JavaScript files using JSHint.
- Grunt-Contrib-CSSLint
- Grunt-Contrib-CSSLint is a grunt task that lint CSS files using JSHint.
- Grunt-NGmin
- Grunt-NGmin is a grunt task that pre-minifies AngularJS files.
- Grunt-Contrib-Uglify
- Grunt-Contrib-Uglify is a grunt task that concat and minifies JavaScript files.
- Grunt-Contrib-CSSMin
- Grunt-Contrib-CSSMin is a grunt task that concat and minifies CSS files.
- Load-Grunt-Tasks
- Load-Grunt-Tasks is a grunt task that automatically loads multiple grunt tasks.
- Grunt-Nodemon
- Grunt-Nodemon is a grunt task that runs nodemon.
- Grunt-Concurrent
- Grunt-Concurrent is a grunt task that runs tasks concurrently.
- Grunt-Mocha-Test
- Grunt-Mocha-Test is a grunt task that runs server side mocha tests.
- Grunt-Karma
- Grunt-Karma is a grunt task that runs karma test runner.
- Karma
- Karma is a test runner for JavaScript.
- Karma-Jasmine
- Karma-Jasmine is a karma adapter for the Jasmine testing framework.
- Karma-Coverage
- Karma-Coverage is a karma plugin that generates code coverage using Istanbul.
- Karma-Chrome-Launcher
- Karma-Chrome-Launcher is a karma launcher for Chrome and Chrome Canary.
- Karma-Firefox-Launcher
- Karma-Firefox-Launcher is a karma launcher for Firefox.
- Karma-Phantomjs-Launcher
- Karma-Phantomjs-Launcher is a karma launcher for PhantomJS.
Bower
Notice that .bowerrc configuration file is used to change the default install location to public/lib.
Bower is a front-end package manager that uses a json file to configure the components your application will use.
Here‘s the description of the front-end components you‘ll use to bootstrap your application.
- Bootstrap
- Bootstrap is a front-end framework containing many common web development components.
- AngularJS
- AngularJS is an open-source JavaScript framework.
- Angular-Cookies
- Angular-Cookies is convenient wrapper for cookies manipulation.
- Angular-Resource
- Angular-Resource provides interaction support with RESTful services.
- Angular-Animate
- Angular-Animate provides JavaScript and CSS3 animation support.
- Angular-Mocks
- Angular-Mocks provides inject and mock support to AngularJS services unit tests.
- Angular-Sanitize
- Angular-Sanitize provides a functionality to sanitize HTML.
- Angular-Bootstrap
- Angular-Bootstrap is a set of bootstrap components written in pure AngularJS.
- Angular-UI-Utils
- Angular-UI-Utils is a set of common utilities for AngularJS.
- Angular-UI-Router
- Angular-UI-Router provides robust routing and deep linking services for AngularJS applications.
Grunt
Grunt is a great tool for automating you JavaScript tasks. The ecosystem is huge, containing many common tasks you can use in your daily development process.
To configure grunt you start with the gruntfile.js file, where you define the tasks you want to run.
We start with two basic tasks:
Default
The default task is the task that runs when you type ‘grunt‘ in your command-line, the default task consists of three sub-tasks:
JSHint
Linter task that keep your JavaScript code free of common mistakes and syntax errors.
CSSLint
Linter task that keep your CSS code free of common mistakes and syntax errors.
Watch
This watches your file system for changes and automatically reloads the application whenever you change certain files.
Nodemon
This runs your Node.js application using nodemon.
Please notice that the last two tasks are wrapped with another task called Concurrent to keep the application continuously running.
Debug
Same as default but will also start node-inspector for debugging.
JSHint
Linter task that keep your JavaScript code free of common mistakes and syntax errors.
CSSLint
Linter task that keep your CSS code free of common mistakes and syntax errors.
Watch
This watches your file system for changes and automatically reloads the application whenever you change certain files.
Nodemon
This runs your Node.js application using nodemon.
Node-Inspector
This runs the node-inspector debugging module.
Please notice that the last two tasks are wrapped with another task called Concurrent to keep the application continuously running.
Lint
This task runs when you type ‘grunt lint‘ in your command-line, the test task consists of two sub-tasks:
JSHint
Linter task that keep your JavaScript code free of common mistakes and syntax errors.
CSSLint
Linter task that keep your CSS code free of common mistakes and syntax errors.
Build
This task runs when you type ‘grunt build‘ in your command-line, the test task consists of two sub-tasks:
JSHint
Linter task that keep your JavaScript code free of common mistakes and syntax errors.
CSSLint
Linter task that keep your CSS code free of common mistakes and syntax errors.
LoadConfig
A task that loads the environmental configuration file for the uglify and cssmin tasks.
NGMin
A task that pre-minifies AngularJS files.
Uglify
A task that concat and minifies JavaScript files.
CSSMin
A task that concat and minifies CSS files.
Remember to use the build task before deploying your application to a production environment.
Test
This task runs when you type ‘grunt test‘ in your command-line, the test task consists of three sub-tasks:
Env:test
This is a simple task that changes the NODE_ENV global environment variable to ‘test‘.
MochaTest
This runs the mocha server tests that are located in the app/tests folder.
Karma:unit
This uses the karma test runner to run the AngularJS unit tests.
We recommend that you visit Grunt‘s Documentation Section to learn more about writing your own tasks, and mainly toexplore the tasks already written by the community.
Express & Routing
Express is web framework for the Node.js platform. Its robustness and minimalism made it very popular among Node.js developers.
Express configuration is done in the config/express.js In the express.js file the application is initialized and configured, automatically loading the routes files in the app/routes folder, which contains the set of routes the application will serve.
There are a few pre-bundled routes:
Authentication Routes
Authentication routes are located in the app/routes/users.server.routes.js file.
- GET http://localhost:3000/users/me
- Returns the current authenticated user.
- POST http://localhost:3000/auth/signup
- This is used to sign up a user using username and password.
- POST http://localhost:3000/auth/signin
- This is used to sign in a user using username and password.
- GET http://localhost:3000/auth/signout
- This is used to sign out the current user.
- GET http://localhost:3000/auth/facebook
- This is used to initialize the Facebook OAuth process.
- GET http://localhost:3000/auth/facebook/callback
- This is used as the callback URI for Facebook OAuth process.
- GET http://localhost:3000/auth/twitter
- This is used to initialize the Twitter OAuth process.
- GET http://localhost:3000/auth/twitter/callback
- This is used as the callback URI for Twitter OAuth process.
- GET http://localhost:3000/auth/linkedin
- This is used to initialize the Linkedin OAuth process.
- GET http://localhost:3000/auth/linkedin/callback
- This is used as the callback URI for Linkedin OAuth process.
- GET http://localhost:3000/auth/google
- This is used to initialize the Google OAuth process.
- GET http://localhost:3000/auth/google/callback
- This is used as the callback URI for Google OAuth process.
- GET http://localhost:3000/auth/github
- This is used to initialize the Github OAuth process.
- GET http://localhost:3000/auth/github/callback
- This is used as the callback URI for Github OAuth process.
Please notice that you can add more authentication options using a Passport Strategy and this pattern.
Application Routes
Application core routes are located in the app/routes/core.server.routes.js file.
- GET http://localhost:3000/
- The main application page. Using AngularJS helps reduce the use of server side templating, and only serve a single application page.
To learn more about this visit the Backend Views section.
Example Routes
An ‘Article‘ example is included with the boilerplate to help you understand how to properly build your RESTful API, the routes for this module are located in the app/routes/articles.server.routes.js file.
- GET http://localhost:3000/articles
- Returns the list of articles.
- POST http://localhost:3000/articles
- Creates a new article.
- GET http://localhost:3000/articles/:articleId
- Returns an article by articleId.
- PUT http://localhost:3000/articles/:articleId
- Updates an article by ID.
- DEL http://localhost:3000/articles/:articleId
- Deletes an article by ID.
To learn more about Express you should visit the Guide Section in the official website.
Passport
Passport is an authentication middleware, which allows you to implement many authentication methods in your Express application.
Passport utilizes a modular approach that uses authentication strategies modules, offering a simple, configurable authentication solutions.
This boilerplate comes pre-bundled with 6 authentication mechanisms implemented in the config/passport.js file:
- Local
- The Local Strategy is used to authenticate users via username and password.
- The Facebook Strategy is used to authenticate users via their Facebook account.
- The Twitter Strategy is used to authenticate users via their Twitter account.
- The Google Strategy is used to authenticate users via their Google account.
- The Linkedin Strategy is used to authenticate users via their Linkedin account.
- Github
- The Github Strategy is used to authenticate users via their Github account.
To understand Passport better we recommend that you visit the Guide Section in the official website.
Backend Views
AngularJS reduces the need for server side templating. What once was a web application served by server as HTML pages can now be implemented using Angular‘s template system.
So why do you still keep a views folder in your app folder?
There are few answers to this question:
- You still need to render the index and error page.
- You might need to render HTML templates for your email notifications.
- You want to render local configuration properties in the template. For instance, the title property from the configuration file can be used in the title element of the HTML page.
- AngularJS module system is implemented in a way that allows you to automatically load the modules .js files in template.
So we can‘t use static templates, and we have to use some kind of template engine, but which one?
Swig Template Engine
Swig is a template engine, written by Paul Armstrong.
While JADE is the default template engine used by Express, and is by far the most popular template engine, it doesn‘t suit this boilerplate for several reasons:
- It‘s slower.
- It uses its own language, steeping the learning curve.
- You don‘t need it! JADE‘s greatest advantage is to facilitate the task of writing a lot of HTML that is being served by the server. You‘re going to use AngularJS client templating engine, thus relieving the need for server templating.
On the other hand, using Swig has a few advantages:
- It‘s faster, as in way faster.
- It uses HTML.
- It has all the features we need to render our index and error pages!
To summarize, when coding a Node.js website, you might want to use other template engines, but approaching web application development using AngularJS, we think Swig is the best choice.
To understand Swig better we recommend that you visit the Official Website.
The Views
There are 4 files in the views folder:
- Layout
- This is most important file, which sets the layout used to render all the other templates.
- Index
- The index template is served as the main application page.
- 404
- The 404 error template is served whenever express cant find a routing scheme for the current path.
- 500
- The 500 error template is served whenever there‘s a server error.
The Templates
The templates folder is placed inside the views folder and currently contains 2 files:
- Reset Password Email
- An email template sent to users after they‘ve request to reset their password.
- Reset Password Confirmation Email
- An email template sent to users after they‘ve reset their password.
Server Tests
We use Mocha to test the server side logic. Mocha tests are asynchronous, easy to maintain, and uses a readable BDD syntax.
Assertions
Mocha needs an external assertion library to predicate the result of each test, in this case Should.js is being used. Should is an expressive library aiming to simplify tests and be readable. It extends the Object.prototype with a single non-enumerable getter that allows you to express how that object should behave.
Test Files
Each entity have its own test file located inside the app/tests folder.
Writing Tests
There are a few common steps we use to test an entity:
- In the beforeEach or before functions take care of prerequisites and create the objects you are about to use in your tests.
- For each test start with a describe function to indicate which method is being tested.
- Next, add your scenario tests using the it function.
- In the it function run the tests functionality and use should to assert what the end result should be.
- Finally use after or afterEach functions to finalize your tests and clear the test database.
To learn more about how to write your tests visit The Article Example Section.
AngularJS Tests
Testing is an important feature of the AngularJS framework. It is so well established that the team has create a very cool to automate tests, the Karma Test Runner.
The Karma Test Runner is a unique testing tool that enables you to automatically test your code on multiple real browsers using Node.js and Socket.io.
Karma is not a testing library, it utilizes other testing frameworks to test your code and comes with different framework adapters, supporting the common testing frameworks.
In the AngularJS documentation the team uses Jasmine Testing Framework to unit test the application. So, in the boilerplate we use Jasmine as well.
Now AngularJS supports two kind of tests:
- E2E
- End-To-End testing enables to test several parts of the application together, so instead of just testing your controller‘s methods, you can actually test different scenarios in your application. To understand it better visit the AngularJS E2E Testing Section.
- Unit
- Unit testing is the more common testing method, which enables you to test different units of the application, it‘s a more detailed kind of testing, which neglects the bigger picture and focuses on the single unit functionality. To understand it better visit the AngularJS Unit Testing Section.
In the example provided there are only unit tests, E2E should come out in the next version.
Karma Configuration
Karma configuration file, karma.conf.js, is the located at the root folder. You can learn more about the different configuration properties in the Configuration Section on the official website.
But here is a quick review of the properties used in the boilerplate:
- Frameworks
- The testing framework you want to karma to use, in this case we‘ll use Jasmine.
- Files
- This is really important! This is the list of files that karma should load before starting the tests.
Notice that we load the angular module tests automatically, so whenever you add a new module, Karma will run your tests without you having to change anything at all.
- LogLevel
- Determines the logging level of karma console output.
- Browsers
- Determines which browsers to launch when testing, the boilerplate comes pre-bundled with 3 launchers: Chrome, Firefox, and PhantomJS.
- SingleRun
- Determines if karma will run one time and return the results, or stay connected to watch for changes.
Notice that karma is executed as a grunt task that looks for the configuration file.
Unit Testing
In the Article examples attached, there‘s a unit test example in the tests/article.spec.js file. Notice that we use angular-mocks to simulate the HTTP requests. The tests are defined to cover all the CRUD operations, and will test the $resource service as well.
There are a few common steps we use to unit test the application:
- In the beforeEach function take care of prerequisites and create the objects you are about to use in your tests.
- For each test start with a describe function to indicate which method is being tested.
- Next, add your scenario tests using the it function.
- In the it function run the tests functionality.
- Finally use Jasmine matchers to test the result.
To learn more about how to write your tests visit The Article Example Section.
AngularJS Modules
When we started with MEAN one of our major concerns was how to structure our AngularJS application, and on the first few AngularJS applications, we used the great AngularJS Seed Project provided by the AngularJS team.
The basic structure for this project is quite simple:
|-css|---app.css|-img|-js|---app.js|---controllers.js|---directives.js|---filters.js|---services.js|-partials|---partial1.html|---partial2.htmlindex.html
Notice that in the JS folder there are a few pre-bundled files. Basically you just place all your controllers in the controllers.js file, all your services in the services.js file, and so on. This is nice for a single developer working on a small project, but when working on production web application, pretty soon you get bloated JS files, which create real issues when trying to work in a team.
Then we changed the structure a bit to look something like this:
|-css |---app.css |-img |-js |---app.js|---controllers|-----controller1.js|-----controller2.js|---directives|-----directive1.js|----- directive2.js|---filters|-----filter1.js|-----filter2.js|---services|-----service1.js|-----service2.js|-partials|---partial1.html|---partial2.htmlindex.html
Reorganizing the project this way helped us create bigger projects that are more maintainable in the long term. For a while we had fun using this but lately we found out that wasn’t enough. Now instead of bloating a single JavaScript file, we had pretty big folders containing ~20 controllers, and even more views in the partials folder.
Luckily, when the original MEAN.IO boilerplate gained some traction, we got a chance to talk to some great AngularJS developers writing blogs and working on some popular libraries. One of the greatest topics in our conversations was Angular’s modularity.
AngularJS Module System
AngularJS module system is a core feature when developing AngularJS applications; actually every AngularJS application is basically an AngularJS module. The other thing about AngularJS modules is that when defining a module you can also include sub-modules as dependencies. It usually looks something like this:
angular.module(‘FirstDependency’, []);angular.module(‘SecondDependency’, []); angular.module(‘MainModule’, [‘FirstDependency’, ‘SecondDependency’]);
In this example we define the first and second modules and then we define the main module with the two sub-modules as dependencies. Later when you want to define an AngularJS entity you can simply use the sub modules as way to separate your application logic. For example defining a controller will look something like this:
angular.module(‘FirstDependency’).controller(…);
AngularJS Horizontal Modules
In their seed project, the AngularJS team recommends using modules in a horizontal way that ends up looking like this:
angular.module(‘application.controllers’, []);angular.module(‘application.services’, []);angular.module(‘application’, [‘application.controllers’, ‘application.services’]);
With this approach you arrange your AngularJS entities in horizontal modules that represents their role:
Application | |||
---|---|---|---|
Controllers | Directives | Filters | Services |
Controller1 | Directive1 | Filter1 | Service1 |
Controller2 | Directive2 | Filter2 | Service2 |
Controller3 | Directive3 | Filter3 | Service3 |
Although this helps create fewer modules those modules wont represent the higher functionality of each entity, for example all the controllers are defined under the same module regardless of their actual purpose. While this is suitable for small projects, using horizontal modules doesn‘t scale well for bigger projects.
Vertical Modules Are Better
During our conversation with some of the main contributors to the popular Angular-UI, they pointed this issue to us. When we observed our AngularJS applications we discovered it would be better to restructure our applications in a vertical manner:
Application | ||
---|---|---|
Core Module | Users Module | Articles Module |
CoreController1 | UsersController1 | ArticlesController1 |
CoreController2 | UsersController1 | ArticlesController2 |
CoreService1 | UsersService1 | ArticlesService1 |
CoreFilter1 | UsersFilter1 | ArticlesFilter1 |
CoreDirective1 | UsersDirective1 | ArticlesDirective2 |
This helped us divide the project logic into modules that represent individual logical units, and it didn‘t surprised us to find out the Angular-UI projects uses the same approach.
New Folder Structure
Using vertical modules only solves half the problem because we still use horizontal approach in our folder structure. This means that all your application controllers will reside in the same folder, as are all the services, directives, filters, and views. In this case you wouldn’t be able to associate a file with its module until you open it.
So we converted our application structure to a vertical structure to fit the vertical modular approach:
|-css |-img |-js |-modules |---articles |-----config |-----controllers |-----services |-----tests |-----views|---core|-----config|-----controllers|-----tests|-----views|---users|-----config|-----controllers|-----services|-----views
In this case we have 3 modules:
- Core
- Containing the application core configuration, controllers, test, and views.
- Users
- Containing the application authentication configuration, controllers, services, and views.
- Articles
- The example module we added, that contains article related configuration, routing, controllers, services, tests, and views.
This structure allow clear separation of functionality and concerns, so just by looking at the folder structure you can start asking questions about your modules, for example why does the users module have no tests? (hint: Its our fault and we plan to add those :)).
But we didn’t want to stop at this point!
Because we are building a full-stack solution, won’t it be great if module files could be automatically included in the backend view HTML, eliminating common import mistakes? We do two things to help with this issue:
- In the config/express.js file, we iterate over the modules folder to automatically add the .JS and .CSS files to the layout HTML.
There two kind of modules you‘ll add to your application: third-party modules and custom modules.
To add third-party modules use the public/config.js file where we added an array property calledapplicationModuleVendorDependencies. When you add a new third-party module you should add it to this array so the main module can load it as a depenedency.
To register your own module, we created the ApplicationConfiguration.registerModule method. To add your custom module and your module and it will automatically be loaded as a dependency to the AngularJS main application module.
This method has a few advantages:
- Team members have a method of organizing their code, so every module will look the same.
- Everyone has a clearer and broader view of the project.
- Working together becomes faster, especially in merging the different development branches.
- Because this is very structured you can start automating some common tasks, like creating a new module, verifying an existing module, etc.(Hmmm... Future Generator)
- You can avoid common mistakes by not including all the JS files, or forget to add your module as a dependency to the main module.
- Reusage of modules is now easier because you can just seamlessly copy your module folder to another project.
- Third party modules can now be easily shared and implemented.
ApplicationConfiguration
While the angular module system is quite robust it lacks a few options, mainly the abiliy to add dependencies to the main module after it was already created. Because of that we use the ApplicationConfiguration object to maintain a list of modules, which the main module will use as depenedencies. If it weren‘t for the ApplicationConfiguration, you would have to register your module in two place:
- When you create your module using the
angular.module(...)
method. - When you create your main application module you‘ll have to register your module as a dependency in the dependencies list.
This can become an annoying pitfull, so we added the ApplicationConfiguration that is loaded before all the modules file. TheApplicationConfiguration global object expose a method named registerModule, this method will create the new angular module and add it to list of dependencies of the main application module.
We recommend that you take a look at the code that is placed inside the /public/config.js file.
Module Structure
So how should you add a new module?
To add a new module, you’ll have to create a new folder in the public/modules folder. The directory structure should look something like this:
|-module |---config |---controllers |---css |---directives |---filters |---img |---services |---tests |---views |---module.js
In each folder you‘ll include the appropriate module entities, you can also delete the empty folders to keep it clean.
Finally you have to add your module.js file, which should look something like this:
‘use strict‘;// Use Applicaion configuration module to register a new moduleApplicationConfiguration.registerModule(‘moduleName‘);
Thats it! This way the registerModule method will create your module and push it to the dependencies list of your AngularJS main application module.
MEAN will take care of everything else, like including those files in the layout HTML and bootstrap the AngularJS application using your module as a dependency.
Module Tests
Adding Karma tests is a simple task, and you can follow the Article Example to learn all about it.
But here is another neat feature: loading your module tests is also done automatically! Karam config file will iterate through the module folder and add your new module tests as well. Don‘t worry! if you haven‘t written any tests karma will skip your module and just run the tests you already have.
Notice: Your test files should be placed in the module/tests folder or else MEAN won‘t ignore them and add them in the HTML as script files.
AngularJS Menus Service
In the 0.3.x version, MEAN.JS has introduced a new AngularJS service that helps you manage your application menus. The menu service has several methods:
- Menus.getMenu(menuId)
- Returns a menu object identified by the menuId argument.
- Menus.addMenu(menuId, [isPublic], [roles])
- Creates a new menu object, which will be identified by the menuId argument. This method also include three arguments:
- menuId (Required) - Indicates the menu identifier for future reference.
- isPublic (Optional; Default: false) - Indicates whether a menu should be displayed only to authenticated users.
- roles (Default: [‘user‘]) - An array indicating the roles that are allowed to view this menu.
- Menus.addMenuItem(menuId, menuItemTitle, menuItemURL, [menuItemUIRoute], [isPublic], [roles]);
- Creates a new menu item object. This method also include couple of arguments:
- menuId (Required) - Indicates the menu identifier.
- menuItemTitle (Required) - A String title for the menu item.
- menuItemURL (Required) - The path this menu item will link to.
- menuItemUIRoute (Optional; Default: menuItemURL) - The UIRoute value, which is used to define the URL scheme where this menu item is marked as active.
- isPublic (Optional; Default: menu.isPublic) - Indicates whether a menu item should be displayed only to authenticated users.
- roles (Optional; Default: [‘user‘]) - An array indicating the roles that are allowed to view this menu item.
- Menus.addSubMenuItem(menuId, rootMenuItemURL, menuItemTitle, menuItemURL, [menuItemUIRoute], [isPublic], [roles]);
- Adds a submenu item to an existing item object. This method also include couple of arguments:
- menuId (Required) - Indicates the menu identifier.
- rootMenuItemURL (Required) - Indicates the root menu item identifier.
- menuItemTitle (Required) - A String title for the menu item.
- menuItemURL (Required) - The path this menu item will link to.
- menuItemUIRoute (Optional; Default: menuItemURL) - The UIRoute value, which is used to define the URL scheme where this menu item is marked as active.
- isPublic (Optional; Default: menu.isPublic) - Indicates whether a menu item should be displayed only to authenticated users.
- roles (Optional; Default: [‘user‘]) - An array indicating the roles that are allowed to view this menu item.
Using the Menus service is usually done in a configuration sections of your application modules. A simple configuration would look like this:
angular.module(‘example‘).run([‘Menus‘, function(Menus) { // Set top bar menu items Menus.addMenuItem(‘topbar‘, ‘Example‘, ‘example‘); }]);
To learn more about the Menus service, visit The Article Example Section.
The Article Example
The Article example is an end-to-end example that includes the basic CRUD operations, which are most commonly used in content websites. It is divided into two parts: The Express backend module, and The AngularJS front-end module.
Express Backend Module
We mostly use the Express application as a RESTful API for the AngularJS application. This means the common MVC architecturecan be reduced to an MC architecture, where the Model represent the data entities in the system, while the Controller is in charge of the business logic, leaving the View part only in the AngularJS application.
Mongoose Model
Mongoose is a Node.js schema-based object-modeling module. Mongoose models are defined using a Schema object that allows you to model and validate your data.
The Mongoose Schema
The Mongoose schema is used to define the structure of your application‘s data. Entries are called Documents in the MongoDB context, and schemas describe what types of properties they have, and what references and relations exist between them.
In our article example, we define the type of each property, as well as a possible default value. When necessary, we can also use properties like "trim" to make sure our data is properly transformed before it is saved.
Using Validations and Middleware
We can make sure the data we save complies with specific validation tests, and reject entries, which do not comply. In our example, we validate the title returns a true result for "title.length", to ensure it isn‘t blank. Similarly, we could run any function on the data being saved, and enforce whatever policy we want.
Middleware is used whenever we want to execute code before or after we run any kind of operation on an entry. This gives us the opportunity to carry out validation, authorization, monitoring and other operations, before (or after) the entry is operated upon.
How statics are defined
We can extended the methods we build into the schema. In our example, we added a "load" method to the article schema, which allows us to automatically load an article, and populate a reference to the document describing the article‘s author.
To learn more about Mongoose you should visit the Official Website.
Express Controller
In MEAN, the controllers are where you‘d query your database, and preform any server-side calculations before relaying the data to the client. In the example articles controller example we define the basic CRUD operations and other required methods:
- create
- The create method creates a new Article document.
- read
- The read method returns a single article.
- update
- The update method updates a single article.
- delete
- The delete method removes a single article.
- list
- The list method returns a list of articles.
- articleByID
- The articleByID method sets the current article object by its ID.
- hasAuthorization
- The hasAuthorization method checks if the current user created the current article.
Express Routes
In order to expose the controller methods as REST endpoints, we assign the controller methods to Express endpoints. This is done in the app/routes/articles.js file. Here we also hook up the middleware used to make sure a request for updating or removing the article is only allowed by an authorized user.
Here are the routes we defined for the article example:
- GET http://localhost:3000/articles
- Returns the list of articles.
- POST http://localhost:3000/articles
- Creates a new article.
- GET http://localhost:3000/articles/:articleId
- Returns an article by articleId.
- PUT http://localhost:3000/articles/:articleId
- Updates an article by ID.
- DEL http://localhost:3000/articles/:articleId
- Deletes an article by ID.
Express Mocha Tests
We use Mocha tests to verify our model. In this case the we added a test example that cover the article save method. The test is self is broken into three parts:
Before Testing
Before we test the article save method, we‘ll create the user object, then save it, and in the callback create a new article object.
The Tests
Now we‘re ready to perform our tests. In the first test we‘ll try to save the article, then use the should assertion libraryto verify it was saved without an error.
In the second test, we‘ll check the article model validation. We‘ll set the title property to an invalid value, then try to the save the document, we‘ll use should again to verify that an error has occurred.
After The Test
Once our testing is over, we can now do cleanup and remove the documents from our test database.
To understand BDD better please visit the Official Mocha Website.
AngularJS Front-End Module
Folder Structure
Each AngularJS module is organized in an isolated folder containing the logical structure of the module functionality. In the Article example case, that folder is located at public/modules/articles. This is the folder structure of the Article module:
- config
- The config folder contains any AngularJS configuration related to the articles module, for instance this folder contains the routes.js file, which defines the AngularJS routing for the articles module.
- controllers
- The controllers folder contains any AngularJS controllers related to the articles module.
- services
- The services folder contains any AngularJS services related to the articles module.
- tests
- The tests folder contains any Jasmine tests related to the articles module.
- views
- The views folder contains any AngularJS partial views related to the articles module.
The module folder structure is dynamic and may contain any components related to that module. While the article example is simple, modules can become much more complex, and may contain several services, controller, directives, etc.
AngularJS Service
The client-side of the article entities is connected to the Express route through an AngularJS Service. In this case, we usengResource to easily connect our RESTful endpoints to Express.
The $resource service supports RESTful CRUD endpoints out of the box, except for the update method which requires specifically defining it to use the PUT verb.
AngularJS Controller
The AngularJS controller is where you‘ll write your logic, in this case the controller is simply corresponding to the RESTful service CRUD operations:
- create
- The create method is used to create new articles.
- remove
- The remove method is used to delete an article.
- update
- The update method is used to update an article.
- findOne
- The findOne method is used to fetch a single article.
- find
- The find method is used to fetch a list of articles.
AngularJS Views
The AngularJS views render the data passed through the controller, in this case each view is a visual representation of a CRUD operation:
- create-article.client.view.html
- The create.html view is used to create an article.
- view-article.client.view.html
- The view.html view is used to present a single article.
- edit-article.client.view.html
- The edit view is used to update an article.
- list-articles.client.view.html
- The list view is used to view a list of articles.
AngularJS Routes
AngularJS use the UI-Router module to define the various routes of the module. Each route is defined using the $stateProviderservice, and defines a path to the template, which will be rendered when navigating to a specific URL.
In this example we configured 4 routes:
- /#!/articles
- When navigating to this URL, UI-Router will render the list-articles.client.view.html view.
- /#!/articles/create
- When navigating to this URL, UI-Router will render the create-article.client.view.html view.
- /#!/articles/:articleId
- When navigating to this URL, UI-Router will render the view-article.client.view.html view.
- /#!/articles/:articleId/edit
- When navigating to this URL, UI-Router will render the edit-article.client.view.html view.
Notice that we define a routing parameter called articleId, to grab it later in the controller and fetch the correct article.
AngularJS Menu Items
Your stack is bundled with an AngularJS Menus Service that enables to add menu items directly from the module configuration file. In the article example you can see how the two menu items are added to the top bar menu in thearticles.client.config.js file:
angular.module(‘articles‘).run([‘Menus‘, function(Menus) { // Set top bar menu items Menus.addMenuItem(‘topbar‘, ‘Articles‘, ‘articles‘, ‘dropdown‘, ‘/articles(/create)?‘); Menus.addSubMenuItem(‘topbar‘, ‘articles‘, ‘List Articles‘, ‘articles‘); Menus.addSubMenuItem(‘topbar‘, ‘articles‘, ‘New Article‘, ‘articles/create‘); }]);
AngularJS Unit Tests
AngularJS Jasmine tests are a bit trickier, but are mostly done in the same way as Mocha.
Before Testing
Before testing the article controller, there a few prerequisites we need to take care of:
- Initialize the global variables.
- Add a Jasmine Matcher that compares objects while ignoring the object methods.
- Load the main application module.
- Use the inject function to:
- Point the global variables to the AngularJS services we are about to use.
- Create a new ArticleController instance.
The Test
Most of your tests will look quite the same and will include similar steps:
- First you‘ll have to create your sample data.
- Then, use Angular-Mocks to set the httpBackend expected response.
- Call the controller method you would like to test.
- Then, use httpBackend.flush() to emulate server response.
- Finally, use a Jasmine matcher to verify the test result.
To understand AngularJS unit testing better, please visit the Unit Testing Section in the official website.
MEANJS DOC