Dạo gần đây mình khá hứng thú với Nodejs và React. Đối với cá nhân mình, khi học công nghệ mới không nhất thiết phải xây dựng một ứng dụng cao siêu nào cả. Thì đó là cũng lý do, mình quyết định xây dựng một blog cá nhân đơn giản nhất. I love basic, mình rất thích những cái đơn giản vì sự đơn giản giúp mình có hứng thú, động lực hơn, không gây cho mình cảm giác chán nản. Còn hơn là đặt mục tiêu xây dựng ứng dụng lớn rồi cũng chẳng đến đâu. Một blog cá nhân đơn giản thì có cái gì để học chứ, mọi người đừng có mindset như vậy nhé. Sẽ có nhiều vấn đề lắm đấy . Đây là Github repo để tham khảo.
Backend
Node server
Express Framework của Nodejs khá nổi tiếng
Basic về MongoDB (NoSQL)
Học cách quản lí MongoDB object modeling
Xây dựng API theo chuẩn RESTful
Frontend
Cấu hình config của webpack
React với các thư viện như Redux, React-Router
Một chút về SASS Đây là những công nghệ sẽ dùng xuyên suốt khi xây dựng blog cá nhân. Let's GOOO!
Trong bài viết này, sẽ không dùng Express application generatorgenerator thay vào đó chúng ta nên tự cấu hình config cho riêng mình. Chứ khi bắt đầu chúng ta cần tạo folder server và trong folder server tạo file app.js có nội dụng như sau:
Chúng ta chắc chắn một điều là tất cả các thư viện cũng cài trong thư mực server với command như sau:
npm i -S path express body-parser express-session cors errorhandler mongoose morgan
Cuối cùng chúng ta cài đặt Nodemon, ở đây mình cài global với câu lệnh như sau:
npm install --g nodemon
Với Nodemon là công cụ khá tuyệt vời, nó giúp chúng ta không phải node app.js nhiều lần khi chúng ta thay đổi nội dung file nào đó. Mọi phiền phức như vậy đã có Nodemon, chúng ta không cần phải re-start nhiều lần khi phát triển sản phẩm. nodemon app.js để restart server.
Tạo Model
Chúng ta tạo model Article có các thuộc tính như sau: timestamp, author, body & title. Trong folder server/models ta tạo file Articles.js với nội dung như sau:
Sau đó chúng cần tạo file routes/api/index.js nhiệm vụ của file này là đăng kí router cho toàn bộ cấu trúc API của hệ thống. Mỗi model sẽ có API tương ứng, một ứng dụng sẽ có rất nhiều Model nên việc tạo file routes/api/index.js sẽ giúp mình quản lí router trong hệ thống một cách hiệu quả hơn.
Công việc xây dựng phía backend coi như là hoàn chỉnh, công việc tiếp theo là test API hoạt động như thế nào nhé. POST localhost:8000/api/articles/ để tạo một blog với body như nhau:
PATCH localhost:8000/api/articles/:id để update blog với body tương tự với như tạo blog
GET localhost:8000/api/articles/:id Hiển thị một blog cụ thể với id
Frontend (React)
Ở phần trên, chúng ta đã tạo API server và được test bằng PostMan. Phần server coi như là ổn, phần tiếp theo chúng ta sẽ xây dựng cấu trúc cho client. Một công việc không hề dễ dàng tí nào. Phía Frontend mình thấy khó khăn nhất là việc quản lí state, việc quản lí state hiệu quả là bài toán đau đầu cho tất cả Frontend Developer, khi mà state bắt đầu phình to ra. Theo như mình được biết thì khi làm việc react thì pattern redux đã làm rất tốt điều này. Việc kết hợp với giữa react với react-redux tạo nên sức mạnh tuyệt vời khi phát triển ứng dụng. Bắt đầu vào xây dựng phía client thôi (go).
Init NPM Config
Chúng ta cài đặt một số thư viên để phục vụ cho quá trình xây dựng ứng dụng, đây là những thư viện cần cài đặt, có khá nhiều thư viện mình cần dùng, lưu ý là câu lệnh phía dưới --save-dev có nghĩa là những thư viện này dành cho môi trường development. Hay nói cách khác là toàn bộ tên thư viện được lưu dưới dạng json với key là devDependencies trong file package.json:
Trong quá trình cài đặt nếu có phát sinh lỗi thì chạy câu lệnh sau:
npm i -D extract-text-webpack-plugin@next
Sau cùng là chúng ta cần đặt những thư viện phục vụ cho môi trường Development. Chúng ta cần cài đặt dependencies. Sự khác nhau giữa devDependencies và dependencies trong npm. Mình có thể giải thích đơn giản như dependencies là những thư viện bắt buộc phải cài đặt, devDependencies là những thư viện phục vụ cho môi trường Production.
npm i -S react moment bootstrap babel-polyfill history prop-types react-dom react-redux react-router-dom react-scripts redux axios
Init Webpack Config
Tạo file webpack.config.js trong thư mục client như sau:
Chúng ta cần tạo một số câu lệnh script trong file package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production",
"start": "webpack-dev-server --mode development --open"
},
...
Khi chạy:
npm run build: dùng cho môi trường production
npm run start: dùng cho môi trường development
Tạo Resources
Việc cấu hình webpack coi như là xong, bây giờ chúng ta tạo folder resource để quản lí các file html,css. Chúng ta folder resources chứa folder scss và file index.html, trong folder scss tạo file style.scss file này có nhiệm vụ khai báo global style cho css, với nội dung như sau:
Trong folder client tạo folder src chứa file index.js, file này là nơi để viết react hoặc import các file css,scss.. để tạo bundle file là main.js trong file webpack.config.js đã cấu hình. File này có nội dung như sau:
import React from 'react';
import createHistory from 'history/createBrowserHistory';
import ReactDOM from 'react-dom';
import { Route, Switch, Router } from 'react-router-dom';
import { App } from './components';
import '../resources/scss/style.scss';
ReactDOM.render(
<Router history={createHistory()}>
<Switch>
<Route path="/" component={App} />
</Switch>
</Router>,
document.getElementBimport React from 'react';
const App = (props) => {
return (
<p>Hello App</p>
)
}
export default App;yId('root'),
);
Cài đặt router & App component
Tiếp theo, tạo folder components có file index.jsx, file này có nhiệm vụ là đăng kí toàn bộ router component cho ứng dụng với nội dung như sau:
Bây giờ, edit file App/index.jsx để thêm route cho App/index.jsx:
import React from 'react';
import { withRouter, Switch, Route } from 'react-router-dom';
import { Home } from '../../components';
const App = (props) => {
return (
<Switch>
<Route exact path="/" component={Home} />
</Switch>
)
}
export default withRouter(App);
Tiếp theo tạo file index.jsx trong directory components/Home như sau:
import React from 'react';
class Home extends React.Component {
render() {
return (
<div className="container">
<h1>LightBlog</h1>
</div>
);
}
}
export default Home;
Sau đó đăng kí components ở components/index.jsx nữa là xong:
export { default as App } from './App';
export { default as Home } from './Home';
Component trên chỉ là để test xem thử hoạt động hay chưa thôi, bây giờ cập nhập nội dung của Home component, nhiệm vụ của Home component là sử dụng comnponent con là Form component để render ra nội dụng của Home:
import React from 'react';
import { Form } from '../../components/Article';
class Home extends React.Component {
render() {
return (
<div className="container">
<div className="row pt-5">
<div className="col-12 col-lg-6 offset-lg-3">
<h1 className="text-center">LightBlog</h1>
</div>
<Form />
</div>
</div>
);
}
}
export default Home;
export { default as App } from './App';
export { default as Home } from './Home';
export { default as Article } from './Article';
Xong phần view của form, bây giờ chúng ta xử lí thao tác trên form, component Form sẽ có nhiệm vụ submit gửi request đến server API để tạo một blog với nội dung tương ứng. Endpoint để tạo blog là POST localhost:8000/api/articles, ta phải edit Article/Form/index.jsx:
Ở trên chúng ta tạo app chưa có quản lí state, ở đây chúng ta sử dụng redux để làm điều này, bài viết này hạn chế nên mình không thể giải thích hết được, bài viết này chỉ là việc áp dụng redux cho ứng dụng.
src/store.js
import { createStore, combineReducers } from 'redux';
import { home } from './reducers';
const reducers = combineReducers({
home,
});
const store = createStore(reducers);
export default store;
Tiếp theo chúng ta tạo reducer cho homesrc/reducers/index.js
export { default as home } from './home';
Cũng giống như folder components tạo file index.js để quản lí toàn bộ component của ứng dụng, cũng giống như reducer vậy.
Ở đoạn code trên mình đã tạo xong server chạy bằng express. Ở bài viết này, mình xem như các bạn đã biết về express rồi nhé . Ở đoạn code trên có một đoạn chúng ta sẽ ít gặp đó là app.use(require('morgan')('dev'));. Mình giới thiệu sơ qua về thư viện này một chút, morgan thực chất là HTTP request logger middleware. Thư viện khá thích hợp cho môi trường development, với morgan sẽ có rất nhiều option để log. Chẳng hạn như nếu có lỗi xảy ra sẽ log error đến Apache file access.log hoặc STDOUT hoặc là một file chỉ định nào đó cũng được. Bạn có thể tìm hiểu nhiều hơn về thư viện này. Đối với app.use(require('morgan')('dev')); sẽ responses đến console . Khá thú vị phải không?
GET localhost:8000/api/articles Liệt kê tất cả các danh số blog đã tạo
DELETE localhost:8000/api/articles/:id Xóa một blog với tham số id
Trước tiên, chúng ta cần tạo folder client cùng cấp với folder với server:
Sau đó chúng ta run npm init để khởi tạo npm để quản lí package:
Việc config bên phía client coi như là xong, công việc bây giờ là viết react trên nền những config ở trên thôi nào. (go) (go).
Một điều lưu ý là khi trong lệnh npm thì phải chạy trong folder client
Trong folder components tạo tiếp folder App có file index.jsx với nội dung:
Nếu hoàn thành bước trên, chúng ta sẽ được kết quả mong đợi như sau:
Nhái hàng một chút khi thành công nào:
Việc tạo form được xem như là hoàn tất:
Khi nhập nội dung title, body & author, khi submit tạo blog. Nếu thành công kết quả khi test ở debug của chorme như sau:
Nếu bạn có trong database có dữ liệu thì kết quả sẽ trong như thế này, hiển tại tất cả các blog với redux, mỗi action trong sẽ tương ứng với việc thay đổi state khác nhau. Hưởng thụ kết quả:
Nhập nội dung của form và submit form xem nào. Mình tin kết quả sẽ không khác kết quả nhau là mấy khi dùng và không dùng redux là mấy, nhưng cấu trúc cách thức sẽ hoàn toàn khác nhau, với redux khi ứng dụng scale up mỗi lúc một lớn, vì dùng redux sẽ đở nhọc nhằng hơn rất nhiều về việc quản lí state đấy. Không phải lúc nào cũng đã dùng react là phải dùng redux đâu nhé . Đây là câu quote của Dan Abramov là creator của Redux có nói một câu:
Giao diện sẽ đơn giản như sau:
Như vậy chúng ta đã hoàn thành xây dựng blog đơn giản, chúng ta học rất nhiều thứ từ front-end đến back-end. Cố gắng hoàn thành 1 chức năng đơn giản nhưng không hề đơn giản với những người bắt đầu đâu nhé, trong quá trình làm theo bài viết sẽ có rất nhiều nút thắt cần được giải quyết và research rất nhiều mới hiểu được các vấn đề. Đừng xem nhẹ những ứng dụng nhỏ nhỏ nhé . Happy Coding.