MeanJS - Full stack development framework based on Javacripts
Để thuận tiện cho việc xây dựng, quản lý và phát triển các trang web, rất nhiều các framework đã được xây dựng. Nổi tiếng nhất trong số đó phải kể đến LAMP bao gồm Linux server, Apache, MySQL và PHP. Tuy nhiên, web hiện đại yêu cầu khả năng tương tác cao hơn đồng nghĩa với việc LAMP stack không ...
Để thuận tiện cho việc xây dựng, quản lý và phát triển các trang web, rất nhiều các framework đã được xây dựng. Nổi tiếng nhất trong số đó phải kể đến LAMP bao gồm Linux server, Apache, MySQL và PHP. Tuy nhiên, web hiện đại yêu cầu khả năng tương tác cao hơn đồng nghĩa với việc LAMP stack không phải là giải pháp tối ưu. Đã có rất nhiều các framework khác được xây dựng dựa trên nền tảng các ngôn ngữ khác nhau như Ruby, Python, Perl,..v.v.. tuy nhiên về cơ bản vẫn dựa trên LAMP và ít có sự phá cách. Thời gian gần đây, nhiều website đã được xây dựng dựa trên NodeJS tuy nhiên vẫn còn hết sức đơn giản vì NodeJS vẫn còn hết sức thô sơ. Bài viết này xin dược phép giới thiệu một framework mới dựa trên NodeJS có khả năng xây dựng một trang web hoàn chỉnh dựa trên ngôn ngữ Javascript, đó là MEANJS
MeanJS là một Framework hoàn toàn mới được xây dựng dựa trên các thành phần bao gồm:
- MongoDB: Một NoSQL database điển hình
- Express: Middleware với database
- AngularJS: Front end framwork
Điểm đặc biệt của MeanJS là được viết hoàn toàn dựa trên Javascript. Mặc dù khởi điểm là một ngôn ngữ thuần view, sử dụng chủ yếu để tương tác với DOM (Documnet Object Model), tuy nhiên sau khi Google giới thiệu V8, một trình biên dịch viết bằng C++ để xây dựng các ứng dụng Javascript trên server, vai trò của Javascript đã thay đổi khi nhiều ứng dụng trên server viết ra đời như NodeJS, SocketJS... Mặc dù vậy các ứng dụng này còn hết sức thô sơ và chỉ có thể đảm nhiệm một chức năng riêng biệt nào đó (real-time, mobile web..). Với sự xuất hiện của MeanJS, chúng ta có thể xây dựng một trang web hoàn toàn dựa trên các chương trình trên
1.1 Cài đặt
1.1.1 Dependencies
NodeJS
NodeJS có thể coi như là nền móng của tất cả các Javascript application trên server. Việc cài dặt NodeJS có thể thực hiện đơn giản trên các hệ điều hành khác nhau:
- Ubuntu với apt-get
$ sudo apt-get install node
- MacOS với homebrew
$ brew install node
- Các hệ điều hành khác có thể tìm các gói cài đặt tại trang chủ của NodeJS
MongoDB
MôngoDB là một NoSQL database điển hình, các ứng dụng hiện đại đang dịch chuyển dần từ việc sử dụng MySQL sang NoSQL database và MeanJS không nằm ngoài xu thế đó. Việc cài đặt MongoDB cũng giống như node, có thể thực hiện đơn giản bằng apt get hoặc brew
Bower và Grunt
$ npm install -g bower
$ npm install -g grunt-cli
1.1.2 Cài đặt MeanJS và khởi tạo MeanJS project
Hướng dẫn cụ thể cho việc cài đặt MeanJS có thể tìm thấy trên trang chủ của MeanJS hoặc trên Github
Về cơ bản chúng ta có thể khởi tạo một MeanJS application bằng việc clone trực tiếp trên Github. Tuy nhiên, chúng ta có thể tạo MeanJS project dùng Yeoman
Yeoman
Giống như các framework khác đều cung cấp các công cụ thể có thể tạo scaffold, chúng ta có thể khởi tạo các files dành cho Mean dùng Yeoman Cài đặt Yeoman rất đơn giản, chỉ với:
$ npm install -g yo
Sau đó, chúng ta cài đặt công cụ Generate cho MeanJS
$ npm install -g generator-meanjs
Để khởi tạo MeanJS project sử dụng Yeoman chúng ta chỉ cần:
yo meanjs
Lúc này trên Yeoman sẽ đưa cho chúng ta các lựa chọn cho project, tuỳ vào yêu cầu của ứng dụng mà lựa chọn các gói cho phù hợp
_-----_ | | |--(o)--| .--------------------------. `---------´ | Welcome to Yeoman, | ( _´U`_ ) | ladies and gentlemen! | /___A___ '__________________________' | ~ | __'.___.'__ ´ ` |° ´ Y ` You're using the official MEAN.JS generator. ? What would you like to call your application? MEAN ? How would you describe your application? Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js ? How would you describe your application in comma seperated key words? MongoDB, Express, AngularJS, Node.js ? What is your company/author name? ThienTd ? Would you like to generate the article example CRUD module? No ? Which AngularJS modules would you like to include? ◯ ngCookies ◯ ngAnimate ◯ ngTouch ❯◯ ngSanitize
Sau khi cài đặt các gói thành công, chúng ta hoàn toàn có thể kiểm tra xem MeanJS đã cài đặt thành công chưa khi khởi tạo server bằng grunt
$ grunt
Truy cập vào local server (localhost:3000), nếu như MeanJS project được khởi tạo thành công, màn hình sẽ trả về như sau:
1.2 Cấu trúc thư mục của MeanJS
Một trong những đặc điểm cơ bản của các web framework hiện đại là việc chia tách Front End và Back End. Cấu trúc thư mục cũng như các file thể hiện rõ điều đó.
ducthien-MBP:example ducthien$ ls -l total 104 -rw-r--r-- 1 ducthien staff 669 Nov 5 22:40 Dockerfile -rw-r--r-- 1 ducthien staff 1053 Nov 4 21:20 LICENSE.md -rwxr-xr-x 1 ducthien staff 48 Nov 5 22:26 Procfile -rw-r--r-- 1 ducthien staff 8904 Nov 5 22:41 README.md drwxr-xr-x 7 ducthien staff 238 Mar 28 18:07 app -rw-r--r-- 1 ducthien staff 463 Mar 28 18:07 bower.json drwxr-xr-x 9 ducthien staff 306 Mar 28 18:07 config -rw-r--r-- 1 ducthien staff 147 Nov 5 22:40 fig.yml -rw-r--r-- 1 ducthien staff 414 Nov 5 00:04 generate-ssl-certs.sh -rw-r--r-- 1 ducthien staff 3681 Nov 5 22:40 gruntfile.js -rw-r--r-- 1 ducthien staff 1375 Nov 4 21:31 karma.conf.js drwxr-xr-x 54 ducthien staff 1836 Mar 28 18:07 node_modules -rwxr-xr-x 1 ducthien staff 1788 Mar 28 18:07 package.json drwxr-xr-x 8 ducthien staff 272 Mar 28 18:08 public -rwxr-xr-x 1 ducthien staff 815 Nov 5 22:41 server.js
package.json
Tất cả các chương trình sử dụng nền NodeJS đều có file package.json và MeanJS cũng không phải ngoại lệ. File này sẽ bao hàm tất cả các gói cần thiết dùng trong MeanJS cũng như tuỳ biết theo từng môi trường
{ "name": "mean", "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js", "version": "0.0.1", "author": "ThienTd", "engines": { "node": "0.10.x", "npm": "1.4.x" }, "scripts": { "start": "grunt", "test": "grunt test", "postinstall": "bower install --config.interactive=false" }, "dependencies": { "express": "~4.10.1", "express-session": "~1.9.1", .... }, "devDependencies": { "supertest": "~0.14.0", "should": "~4.1.0", "grunt-env": "~0.4.1", ... } }
bower.json
Nếu như package.json chứa đựng các gói cần thiết cho Back End thì bower.json bao hàm các packages dành cho Front End
{ "name": "mean", "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.2", "angular-ui-utils": "~0.1.1", "angular-ui-router": "~0.2.11" } }
chúng ta có thể dễ dàng nhận ra các gói quen thuộc của AngularJS như angular-touch hay angular-resourse
app
ducthien-MBP:app ducthien$ tree . . ├── controllers │ ├── core.server.controller.js │ ├── errors.server.controller.js │ ├── users │ │ ├── users.authentication.server.controller.js │ │ ├── users.authorization.server.controller.js │ │ ├── users.password.server.controller.js │ │ └── users.profile.server.controller.js │ └── users.server.controller.js ├── models │ └── user.server.model.js ├── routes │ ├── core.server.routes.js │ └── users.server.routes.js ├── tests │ └── user.server.model.test.js └── views ├── 404.server.view.html ├── 500.server.view.html ├── index.server.view.html ├── layout.server.view.html └── templates ├── reset-password-confirm-email.server.view.html └── reset-password-email.server.view.html
Về cơ bản app bao gồm các file và folers dành cho server side. Với những người đã quen với mô hình MVC có thể dễ dàng nhận ra các folder như models, controllers routes hay tests. Điểm lưu ý duy nhất khác biệt với các mô hình khác là views không đóng vai trò quan trọng vì đã có phần Front End riêng. Có thể coi rằng bên trong app bao gồm MC(Model , Controller)
public
Đây là nơi chứa đựng tất cả những gì cần thiết cho Front End
-rw-r--r-- 1 ducthien staff 730 Nov 4 21:29 application.js -rw-r--r-- 1 ducthien staff 833 Mar 28 18:07 config.js -rwxr-xr-x 1 ducthien staff 191 Nov 5 22:26 humans.txt drwxr-xr-x 14 ducthien staff 476 Mar 28 18:08 lib drwxr-xr-x 4 ducthien staff 136 Mar 28 18:07 modules -rwxr-xr-x 1 ducthien staff 32 Nov 5 22:26 robots.txt
Nơi đáng lưu ý nhất bên trong public là folder modules, nơi chứa đựng các view cũng như function được phân chia theo theo mô hình MVC của AngularJS. Trong modules, folder core sẽ là nơi khởi tạo dành cho **Front End ** và các các folder khác tuỳ theo model mà developer mong muốn. Giống như mô hình MVC, bên trong mỗi folder đều có đủ 3 thành phần
core/ ├── config │ └── core.client.routes.js ├── controllers │ ├── header.client.controller.js │ └── home.client.controller.js ├── core.client.module.js ├── css │ └── core.css ├── img │ ├── brand │ │ ├── favicon.ico │ │ └── logo.png │ └── loaders │ └── loader.gif ├── services │ └── menus.client.service.js ├── tests │ ├── header.client.controller.test.js │ └── home.client.controller.test.js └── views ├── header.client.view.html └── home.client.view.html
Mỗi module sẽ đi kèm với ng-controller riêng biệt và từ đây chúng ta có thể định nghĩa các services cũng như directives trên AngularJS
Config files
Ngoài các files và folder config dành riêgn cho Front End và Back end, MeanJS cung cấp hệ thống file cấu hình dành cho cả ứng dụng:
config/ ├── config.js ├── env │ ├── all.js │ ├── development.js │ ├── production.js │ ├── secure.js │ └── test.js ├── express.js ├── init.js ├── passport.js ├── sslcerts └── strategies ├── facebook.js ├── github.js ├── google.js ├── linkedin.js ├── local.js └── twitter.js
Chúng ta có thể chia cấu hình ra làm các loại cơ bản sau:
- Cấu hình chung: config.js, init.js
- Cấu hình dành cho các môi trường env/
- Cấu hình dành cho các ứng dụng thành phần (express, passport, ssl)
- Cấu hình tuỳ biến strategies
CRUD - Create, Read, Update, Delete bao hàm những chức năng cơ bản mà các trang web phổ biến phải cho. Tương tự như các framework khác, MeanJS có thể tạo ra các CRUD model sử dụng Yeoman
ducthien-MBP:sample-app ducthien$ yo meanjs:crud-module books ? Which supplemental folders would you like to include in your angular module? css, img, directives, filters ? Would you like to add the CRUD module links to a menu? Yes ? What is your menu identifier(Leave it empty and press ENTER for the default "topbar" menu)? topbar create app/controllers/books.server.controller.js create app/models/book.server.model.js create app/routes/books.server.routes.js create app/tests/book.server.model.test.js create app/tests/book.server.routes.test.js create public/modules/books/config/books.client.routes.js create public/modules/books/controllers/books.client.controller.js create public/modules/books/services/books.client.service.js create public/modules/books/tests/books.client.controller.test.js create public/modules/books/config/books.client.config.js create public/modules/books/views/create-book.client.view.html create public/modules/books/views/edit-book.client.view.html create public/modules/books/views/list-books.client.view.html create public/modules/books/views/view-book.client.view.html create public/modules/books/books.client.module.js
Chỉ với câu lệnh yo meanjs:crud-model books chúng ta có thể khởi tạo cả *Front End và Back end dành cho books. Dựa trên các files và folders đã được tạo ra bởi Yeoman
Back end
Như đã đề cập ở phần trên, phần Back end của MeanJS thực chất chỉ bao hàm M-Model và C-Controller
Controller
Dựa trên các request từ phía client để xử lý sử dụng các action cơ bản (create, read, list, update, delete)
'use strict'; /** * Module dependencies. */ var mongoose = require('mongoose'), errorHandler = require('./errors.server.controller'), Book = mongoose.model('Book'), _ = require('lodash'); /** * Create a Book */ exports.create = function(req, res) { var book = new Book(req.body); book.user = req.user; book.save(function(err) { if (err) { return res.status(400).send({ message: errorHandler.getErrorMessage(err) }); } else { res.jsonp(book); } }); }; ...
Ngoài ra ta hoàn toàn có thể định nghĩa thêm các action khác để đảm bảo chức năng của website
Model
Sử dụng để định dạng dữ liệu.
'use strict'; /** * Module dependencies. */ var mongoose = require('mongoose'), Schema = mongoose.Schema; /** * Book Schema */ var BookSchema = new Schema({ name: { type: String, default: ', required: 'Please fill Book name', trim: true }, description: { type: String, default: ', required: 'Please fill the description of book', trim: true }, author: { type: String, default: ', required: 'Please enter the authors of the book', trim: true }, created: { type: Date, default: Date.now }, user: { type: Schema.ObjectId, ref: 'User' } });
Nếu như sau khi Yeoman khởi tạo, books chỉ bao gồm có 2 trường chính là name, created và user, chúng ta có thể thêm và bớt định dạng của book tuỳ biến theo yêu cầu được đưa ra
Front End
Như đã đề cập ở phía trên, MeanJS sử dụng AngularJS để xây dựng Front End. Các thư viện cần thiết có thể thêm vào bower.json. Trong quá trình khởi tạo sử dụng Yeoman, link tới books đã được thêm vào header của Website
BooksController sẽ định nghĩa các request tới server cho phù hợp với crud model. Trong trường hợp chúng ta thay đổi các trường của dữ liệu thì cần phải thay đổi dữ liệu lấy từ view trước khi gửi request tới server
angular.module('books').controller('BooksController', ['$scope', '$stateParams', '$location', 'Authentication', 'Books', function($scope, $stateParams, $location, Authentication, Books) { $scope.authentication = Authentication; // Create new Book $scope.create = function() { // Create new Book object var book = new Books ({ name: this.name, description: this.description, author: this.author }); // Redirect after save book.$save(function(response) { $location.path('books/' + response._id); // Clear form fields $scope.name = '; $scope.desciption = '; $scope.author = '; }, function(errorResponse) { $scope.error = errorResponse.data.message; }); }; ...
Tuy nhiên, chúng ta cần phải thêm các trường cần thiết vào trong views để có thể lấy và hiển thị dữ liệu đúng theo CRUD model
books/views/ ├── create-book.client.view.html ├── edit-book.client.view.html ├── list-books.client.view.html └── view-book.client.view.html
Dưới đây là kết quả: List of books (http://localhost:3000/#!/books)
Detail of book
MeanJS ra đời tuy chưa lâu nhưng thực ra đang tạo ra một cơn sốt mới dành cho những nhà phát triển ứng dụng. Với MeanJS, ngoài việc tận dụng được hiệu năng cực kỳ tốt của các ứng dụng Javascript, MeanJS còn cho phép tuỳ biến khá tốt. Với MeanJS, ta có thể xây dựng một trang web hoàn thiện sử dụng Javascript hoặc sử dụng như một End user service point của một Data server thuần tuý.