nl-mean程序下载
在“ 掌握MEAN :MEAN堆栈简介 ”中,您安装并配置了MEAN开发环境。 在本文中,我将通过逐步介绍您创建的示例MEAN.JS应用程序,使您进一步熟悉MEAN堆栈的四个关键部分-MongoDB,Express,AngularJS和Node.js。 浏览该应用程序时,您将遵循从服务器端到客户端的传入HTTP请求。
通过键入mongod
启动本地MongoDB实例。 (或者,在类似UNIX®的操作系统上,您可以键入mongod &
在后台启动该过程。)接下来,将cd
转到上一篇文章中创建的测试目录,然后键入grunt
来启动使用该应用程序创建的应用程序。 Yeoman发电机。 您将看到类似于清单1所示的输出。
清单1.启动本地MEAN.JS应用程序
$ grunt
Running "jshint:all" (jshint) task
>> 46 files lint free.
Running "csslint:all" (csslint) task
>> 2 files lint free.
Running "concurrent:default" (concurrent) task
Running "nodemon:dev" (nodemon) task
Running "watch" task
Waiting...
[nodemon] v1.0.20
[nodemon] to restart at any time, enter 'rs'
[nodemon] watching: app/views/**/*.* gruntfile.js server.js config/**/*.js app/**/*.js
[nodemon] starting 'node --debug server.js'
debugger listening on port 5858
NODE_ENV is not defined! Using default development environment
MEAN.JS application started on port 3000
在浏览器中打开http:// localhost:3000以查看应用程序的主页,如图1所示。
图1.您本地的MEAN.JS主页
现在,您将在目录结构中四处查看,以了解使该应用程序产生变化的原因。 (有关更多信息,请参见MEAN.JS文档中的“ 文件夹结构”页面。)
“现在,您将在目录结构中四处查看,以了解使该应用程序起作用的原因。 ”
了解Node.js和Bower配置文件
稍后我将介绍源代码。 首先,我将快速重新访问package.json,这是您在上一篇文章中了解到的Node.js配置文件。 然后,我将介绍有关其客户端对应文件bower.json的内容。 这两个文件都在项目的根目录中。
package.json
可以说,任何Node.js应用程序中最重要的配置文件是package.json。 在此文件中,您将找到提供给Yeoman生成器的有关应用程序的元数据(例如名称,描述和作者),如清单2所示的package.json部分。
清单2. package.json,第1部分
{
"name": "test",
"description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
"version": "0.0.1",
"author": "Scott Davis",
"engines": {
"node": "0.10.x",
"npm": "1.4.x"
},
接下来,您将看到可以在命令提示符下键入的一系列命令,如清单3所示。
清单3. package.json,第2部分
"scripts": {
"start": "grunt",
"test": "grunt test",
"postinstall": "bower install --config.interactive=false"
},
您已经输入grunt
来启动应用程序。 稍后,您将输入grunt test
来运行单元测试。 postinstall
钩子是您在服务器端依赖项和客户端依赖项之间划分的第一个提示。
但是,这个最重要的文件中最重要的部分列出了应用程序的依赖关系,如清单4所示。这些CommonJS模块都在房子的服务器端运行。
清单4. package.json,第3部分
"dependencies": {
"express": "~4.2.0",
"mongoose": "~3.8.8"
},
"devDependencies": {
"grunt-mocha-test": "~0.10.0",
"grunt-karma": "~0.8.2",
"karma": "~0.12.0",
"karma-jasmine": "~0.2.1",
"karma-coverage": "~0.2.0",
"karma-chrome-launcher": "~0.1.2",
"karma-firefox-launcher": "~0.1.3",
"karma-phantomjs-launcher": "~0.1.2"
}
在dependencies
块中声明了运行时依赖关系(例如,用于路由的Express和用于连接到MongoDB的Mongoose)。 在devDependencies
块中声明了开发人员和构建时依赖项(包括Mocha,Jasmine和Karma等测试框架)。
bower.json
现在,将重点转移到客户端。 浏览器中加载JavaScript库在bower.json中定义,如清单5所示。
清单5. bower.json
{
"name": "test",
"version": "0.0.1",
"description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
"dependencies": {
"bootstrap": "~3",
"angular": "~1.2",
"angular-resource": "~1.2",
"angular-mocks": "~1.2",
"angular-cookies": "~1.2",
"angular-animate": "~1.2",
"angular-touch": "~1.2",
"angular-sanitize": "~1.2",
"angular-bootstrap": "~0.11.0",
"angular-ui-utils": "~0.1.1",
"angular-ui-router": "~0.2.10"
}
}
如您所见,bower.json与package.json类似。 它包含一些相同的元数据字段,并且使用dependencies
块来定义客户端依赖项,例如Bootstrap(用于外观和响应性Web设计)和AngularJS(用于客户端单页应用程序)。
同样,应用程序的源代码分为两个关键目录:一个用于服务器端,一个用于客户端端。
了解目录结构
这个MEAN应用程序有四个主目录,如清单6所示。
清单6. MEAN目录结构
$ ls -ld */
drwxr-xr-x+ 7 scott staff 238 Jun 6 14:06 app/
drwxr-xr-x+ 8 scott staff 272 Jun 6 14:06 config/
drwxr-xr-x+ 49 scott staff 1666 Jun 6 14:07 node_modules/
drwxr-xr-x+ 8 scott staff 272 Jun 6 14:06 public/
-
应用程式
- 包含服务器端源代码。 配置
- 包含配置文件。 node_modules
- 包含package.json中指定的服务器端模块。 上市
- 包含客户端源代码,包括lib目录,该目录包含bower.json中指定的客户端库。
您将把精力集中在应用程序和公共目录上。 寻找应用程序主页的难以捉摸的源代码始于app目录。
探索MEAN堆栈的服务器端
清单7显示了应用程序目录结构。
清单7.应用程序(服务器端)目录结构
$ tree app
app
|--- controllers
| |--- articles.server.controller.js
| |--- core.server.controller.js
| |--- users.server.controller.js
|--- models
| |--- article.server.model.js
| |--- user.server.model.js
|--- routes
| |--- articles.server.routes.js
| |--- core.server.routes.js
| |--- users.server.routes.js
|--- tests
| |--- article.server.model.test.js
| |--- user.server.model.test.js
|--- views
|--- 404.server.view.html
|--- 500.server.view.html
|--- index.server.view.html
|--- layout.server.view.html
如果您花了很多时间编写服务器端MVC应用程序,那么您将了解典型的工作流程:
- 传入的HTTP请求命中路由器。
- 路由器找到合适的控制器来处理请求。
- 控制器从数据库中构建一个模型(或模型列表)并将其传递给视图。
- 该视图通过将模型与模板组合在一起来构建HTML页面,然后将完成的输出传递给等待的HTTP响应。
清单8中显示的app / routes / core.server.routes.js文件(属于Express框架)包含应用程序的关键入口点。
清单8. app / routes / core.server.routes.js
'use strict';
module.exports = function(app) {
// Root routing
var core = require('../../app/controllers/core');
app.route('/').get(core.index);
};
该路由器定义了单个路线- /
-由所述处理index
核心控制器的功能。 注意,核心控制器是Common d模块, require
d in。
'use strict';
清单8开头的语句使您JavaScript运行时进入严格模式,这比过去JavaScript运行时的语法“一切都行”的态度要宽容。 在严格模式下,JavaScript运行时将诚实的错误(例如,意外使变量全局化,或尝试使用以前未定义的变量)视为语法错误。 严格模式与JSHint结合使用,可以确保在开发而不是生产中捕获语法错误。 (当然,实现无错误发布的最终关键是在单元测试中覆盖一定数量的代码。)
接下来,查看app / controllers / core.server.controller.js(也是Express框架的一部分),如清单9所示。
清单9. app / controllers / core.server.controller.js
'use strict';
/**
* Module dependencies.
*/
exports.index = function(req, res) {
res.render('index', {
user: req.user || null
});
};
index
函数接受传入的HTTP请求和传出的HTTP响应。 由于此特定请求不需要数据库中的任何内容,因此不会实例化任何模型。 index
模板以及将替换模板中名称相同的占位符的JSON变量块将呈现到响应中。
接下来是app / views / index.server.view.html,如清单10所示。
清单10. app / views / index.server.view.html
{% extends 'layout.server.view.html' %}
{% block content %}
<section data-ui-view></section>
{% endblock %}
尽管清单11中显示的app / views / layout.server.view.html链接看起来很有希望,但是这里没有什么可看的。
清单11. app / views / layout.server.view.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{{title}}</title>
<!-- General META -->
<meta charset="utf-8">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- Semantic META -->
<meta name="keywords" content="{{keywords}}">
<meta name="description" content="{{description}}">
现在,您开始看到一些看起来很熟悉HTML。 title
, keywords
和description
周围的{{}}
分隔description
将它们标识为Swig占位符,应替换为实际值。 Swig是MEAN.JS Yeoman生成器安装的模板引擎。
但是,如果回头看一下清单9中的core
控制器,您会看到传递到此模板的唯一值是user
。 如果您怀疑其他占位符是配置文件中某个位置定义的默认值,那么您来对地方了。
了解配置和环境
查看清单12中所示的config / env / all.js,其中包含title
, description
和keywords
变量。 (我在目录结构中进行了搜索,以查找定义这些值的位置,这是您可能希望在了解MEAN堆栈时添加到探索性工具箱中的一项技术。)
清单12. config / env / all.js
'use strict';
module.exports = {
app: {
title: 'Test',
description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
keywords: 'MongoDB, Express, AngularJS, Node.js'
},
port: process.env.PORT || 3000,
templateEngine: 'swig',
除了模板期望的关键字之外,此文件中还包含其他一些有趣的值,例如port
和templateEngine
。
环境变量
PORT
和NODE_ENV
是可以在应用程序外部设置以更改其内部行为的两个环境变量示例。 例如,注意config / env / all.js中的port
设置:
port: process.env.PORT || 3000,
此设置对您的应用程序说:“将内部port
变量设置为PORT
环境变量的值,或者如果找不到PORT
则将默认值设置为3000
”
要测试此设置,请按Ctrl + C停止应用程序。 可以使用PORT=4000 grunt
,而不是使用赤裸的grunt
命令重新启动它。 您的应用程序现在在端口4000上运行。
您可以根据运行时所处的运行时环境的类型(开发,生产,暂存,测试等)对Node.js应用程序进行编码,使其行为不同。Express与PORT
变量一样,提供默认值- development
-如果您未明确设置NODE_ENV
以指定运行时环境, NODE_ENV
。 这说明了重新启动应用程序时发出的轻微抱怨:
NODE_ENV is not defined! Using default development environment
在环境变量中外部化运行时配置是一种增加灵活性的聪明方法。 可以在命令行上以临时方式设置诸如PORT
和NODE_ENV
变量。 此功能使为开发和测试目的而翻转变量的值变得很简单。 (当然,您可以通过将它们添加到.bash_profile或在Windows®中,在“控制面板”中对其进行设置来延长它们的使用寿命。)
您也可能出于安全原因考虑使用环境变量。 在环境变量中存储用户名,密码和连接URL会使它们脱离配置文件(以及扩展名,源代码控制),在这些文件中它们可能遭到破坏。 这种方法还可以轻松地在多台开发人员或生产机上部署一组通用的配置文件,并允许每台计算机通过本地环境变量注入唯一的值或凭据。
您不仅限于PORT
和NODE_ENV
环境变量。 平台即服务(PaaS)提供程序通常会提供几个特定于服务的变量供您设置。
命名环境
设置单个环境变量是可以的,但是您可能有一组所有必须一致更改的相关变量。 例如,您要避免更改用户名而不更改相应密码的简单错误。 值得庆幸的是,该MEAN应用程序支持命名环境的概念。 (这个想法并不是MEAN应用程序所独有的。Rails,Grails和许多其他流行的Web框架提供类似的功能。)
在清单13的目录树中查看config / env,您将在适当的位置看到几个命名的环境文件。
清单13. config目录结构
$ tree config/
config/
|--- config.js
|--- env
| |--- all.js
| |--- development.js
| |--- production.js
| |--- test.js
|--- express.js
|--- init.js
|--- passport.js
|--- strategies
|--- facebook.js
|--- google.js
|--- linkedin.js
|--- local.js
|--- twitter.js
2 directories, 13 files
在config / env中,development.js,production.js和test.js均指定命名环境。 如果您猜到all.js包含所有环境通用的值,请拍一下自己。
要查看这些文件的读取和合并位置,请查看config / config.js,如清单14所示。
清单14. config / config.js
/**
* Module dependencies.
*/
var _ = require('lodash');
/**
* Load app configurations
*/
module.exports = _.extend(
require('./env/all'),
require('./env/' + process.env.NODE_ENV) || {}
);
Lo-dash是一个CommonJS模块,它为数组,对象和JSON结构提供便利功能。 在清单14中 ,开发人员的意图是在all.js中设置一些基本值,并允许它们被development.js(或production.js或test.js)中的值覆盖。
您在清单12中看到了config / env / all.js。 清单15显示了config / env / development.js。
清单15. config / env / development.js
'use strict';
module.exports = {
db: 'mongodb://localhost/meanjs-dev',
app: {
title: 'MeanJS - Development Environment'
},
理想情况下, lodash.extend
函数将合并两个JSON块以产生以下结果:
app: {
title: 'MeanJS - Development Environment',
description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
keywords: 'MongoDB, Express, AngularJS, Node.js'
}
不幸的是,这不是您获得的输出。 添加一行代码以将合并后的结构输出到config / config.js,如清单16所示:
清单16.将实际的合并结果记录到控制台
/**
* Load app configurations
*/
module.exports = _.extend(
require('./env/all'),
require('./env/' + process.env.NODE_ENV) || {}
);
console.log(module.exports)
通过键入PORT=4000 NODE_ENV=development grunt
重新运行应用程序。 控制台显示:
app: { title: 'MeanJS - Development Environment' }
似乎config / env / development.js中的JSON结构正在覆盖config / env / all.js中的结构,而不是与之合并。 幸运的是,您可以快速更改config / config.js以获得预期的结果。
将函数调用从_.extend
更改为_.merge
。 当您再次重新运行该应用程序时,您应该看到预期的结果:
app:
{ title: 'MeanJS - Development Environment',
description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
keywords: 'MongoDB, Express, AngularJS, Node.js' },
如果单击浏览器主页上的View> Source ,则可以看到与HTML模板合并的配置值,如清单17所示。
清单17.正确HTML合并结果
<head>
<title>MeanJS - Development Environment</title>
<!-- Semantic META -->
<meta name="keywords" content="MongoDB, Express, AngularJS, Node.js">
<meta name="description" content="Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js">
现在是时候从服务器端移到客户端,以完成此MEAN应用程序的徒步之旅。
探索MEAN堆栈的客户端
主页的关键部分(如清单18所示,在app / views / layout.server.view.html中定义)由客户端的AngularJS填充。
清单18. app / views / layout.server.view.html
<body class="ng-cloak">
<header data-ng-include="'/modules/core/views/header.client.view.html'"
class="navbar navbar-fixed-top navbar-inverse"></header>
<section class="content">
<section class="container">
{% block content %}{% endblock %}
</section>
</section>
回想一下,应用程序目录包含MEAN应用程序的Express服务器端部分。 您有两个提示, header
是由AngularJS在客户端管理的。 首先,每当您看到其中包含ng
HTML属性时,即表明ng ularJS管理该属性。 其次,更实用的是,包含所有服务器端代码的app目录不包含modules目录。 通过消除服务器端作为可能的解决方案,可以将客户端源代码保留在公共目录中。 显然,modules目录位于public目录下,如清单19所示。
清单19.公共(客户端)目录结构
$ tree -L 1 public/
public/
|--- application.js
|--- config.js
|--- lib
|--- modules
如果您查看lib,则将看到几个第三方库:
清单20.第三方库的public / lib目录
$ tree -L 1 public/lib
public/lib
|--- angular
|--- angular-animate
|--- angular-bootstrap
|--- angular-cookies
|--- angular-mocks
|--- angular-resource
|--- angular-sanitize
|--- angular-touch
|--- angular-ui-router
|--- angular-ui-utils
|--- bootstrap
|--- jquery
回想一下,这些是bower.json中指定的相同库。
但是,如果您在modules目录中窥探一下,则会在app / views / layout.server.view.html中找到指定的modules / core / views / header.client.view.html模板。
清单21.模块/core/views/header.client.view.html
<div class="container" data-ng-controller="HeaderController">
<div class="navbar-header">
<button class="navbar-toggle" type="button" data-ng-click="toggleCollapsibleMenu()">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/#!/" class="navbar-brand">MeanJS</a>
</div>
如果您将MeanJS
class="navbar-brand"
锚的值从MeanJS
更改为其他值,则在保存文件后,更改立即反映在浏览器中。 但是,通往主要负载(主页的主要内容)的路径更加circuit回。 再次查看app / views / layout.server.view.html,如清单22所示。
清单22. app / views / layout.server.view.html
<body class="ng-cloak">
<header data-ng-include="'/modules/core/views/header.client.view.html'"
class="navbar navbar-fixed-top navbar-inverse"></header>
<section class="content">
<section class="container">
{% block content %}{% endblock %}
</section>
</section>
container
部分内部是一个名为content
的block
。 记住无害的app / views / index.server.view.html:
{% extends 'layout.server.view.html' %}
{% block content %}
<section data-ui-view></section>
{% endblock %}
该block content
包含具有data-ui-view
属性的空白部分。 客户端AngularJS路由器使用此属性。 查看public / modules / core / config / core.client.routes.js,如清单23所示。
清单23. app / views / index.server.view.html
'use strict';
// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// Redirect to home view when route not found
$urlRouterProvider.otherwise('/');
// Home state routing
$stateProvider.
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html'
});
}
]);
从直观上看,这不是显而易见的,但是此客户端路由器将模块/core/views/home.client.view.html模板(如清单24所示)注入到包含以下内容的app / views / index.server.view.html部分中:网址为/
时,为data-ui-view
属性。 当您在MEAN应用程序的主页上时,此模板的内容应与您在浏览器中看到的内容匹配。
清单24. modules / core / views / home.client.view.html
<section data-ng-controller="HomeController">
<h1 class="text-center">THANK YOU FOR DOWNLOADING MEAN.JS</h1>
<section>
<p>
Before you begin we recommend you read about the basic building
blocks that assemble a MEAN.JS application:
</p>
结论
在本文中,您逐步了MEAN应用程序的关键部分。 在服务器端,您了解到该路径以Express路由开头,依次调用Express控制器功能,这些功能又将JSON数据与Swig模板合并,然后将其返回给客户端。 但是过程并没有就此结束。 在客户端,AngularJS路由会提取HTML模板并将其注入主页。
下次,通过探索应用程序的文章部分,您将更深入地了解MongoDB与AngularJS一起扮演的角色。 您还将看到在服务器端和客户端上的测试如何确保最小化生产中的意外行为。
在此之前,请尽情掌握MEAN堆栈。
翻译自: https://www.ibm.com/developerworks/opensource/library/wa-mean2/index.html
nl-mean程序下载