概要
記事を投稿、管理できるアプリを作成した。機能としては、アカウント登録、ログイン機能、記事作成&編集&削除機能がある。見た目は以下のようになる。
見た目
見た目は以下のようになる。
ソースコード
ソースコードをgithubにアップした。
https://github.com/akikisai/Article-management-app
使用したライブラリー
使用したものやバージョンは以下になる。
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"ejs": "~2.6.1",
"express": "~4.16.1",
"express-session": "^1.17.2",
"http-errors": "~1.6.3",
"moment": "^2.29.1",
"mongodb": "^4.4.0",
"morgan": "~1.9.1"
環境構築
まず環境構築を行う。
node.js環境構築
以下のリンクからnode.js推奨版をダウンロードし、特に何も変更せずインストーラーの流れに沿ってインストールする。これでnpmコマンドが使えるようになる。
node.jsダウンロードサイト
mongoDB環境構築
以下のリンクの内容に沿って環境構築する。
mongoDB環境構築
mongo
コマンドを打ってmongo shellが現れれば成功。
プロジェクト作成
デスクトップ上にプロジェクトを作成したい。まずcd
コマンドで移動し、アプリケーションを素早く作成できるようにするためexpressをインストールする。
$ cd Desktop
$ npm install express-generator -g
textappというプロジェクトを作成する。この時デスクトップにtextappフォルダーが作られる。
その後textappフォルダーな中に入り、npm install
で初期のパッケージを使用できるようにインストールする。
$ express -e textapp
$ cd textapp
$ npm install
※テキストエディタを使うが、ない場合visual studio codeもしくはatomが推奨。
visual studio code公式ページ
Atom公式ページ
Node.jsでは、変更を有効にするためにプロセスを再起動する必要があるが、nodemon
を使用してプロセスを自動的に再起動するので、余分な手順を排除る。これをインストールする。
$ npm install nodemon -g
package.json
ファイル内の"start": "node ./bin/www"を以下のように変更し、これでnodemonに対応できる。
"start": "nodemon ./bin/www"
npm start
でプロジェクト起動する。
$ npm start
ファイル内にポートが3000と設定されていることがわかり、
binファイル > wwwファイル > var port = normalizePort(process.env.PORT || '3000');
ウェブサイトに以下のリンクを入力すると、
http://localhost:3000/
welcome to expressが表示される。
ここで注意したいのが、次の作業に当たり、npm start
を入力したターミナルは閉じないこと。
mongoDBと接続
mongoDBの環境構築は済んでいて、ここでは新しいgit bashを開き、以下のコマンドでデータベース保存場所を決める。この場合C:\mongodb\dataに保存している。
$ mongod --dbpath "C:\mongodb\data"
mongoDBと接続するためには、npm start
を入力したシェルと、mongo
コマンドを打って出てきたmongoシェルが同時に存在しなければならない。mongo
コマンドを打って出てきたmongoシェルがあるということはmongoDBに接続成功。なお、ターミナルにおいてmongoシェルにうまく入力できない場合、windowsのコマンドプロンプトでも大丈夫。
$ mongo
mongoDBとつなぎ、shell を使えるようになる。
データベースの中身を確認
>show dbs
デフォルトはお以下のようになる。
admin 0.000GB
config 0.000GB
local 0.000GB
textappというデータベース作成
use textapp
userコレクションを作る。
db.createCollection('users');
コレクションを表示する。
show collections
正しく表示される。
nodejsとmongodbを接続するために、mongodb nodejs driverを使う。
※ほかにもMongooseを使用する方法がある、こっちのほうが人気らしい。
インストール含め使い方はmongodb nodejs driverドキュメント参照。
cd textapp
でtextappフォルダ内でmongodb nodejs driverをインストールする。
npm install mongodb --save
ドキュメントの例を参考にし、mongodbに接続するコードを書く。ファイルの新規作成などの細かい手順は全部省略する(githubソースコードを見ればわかるので)この記事では主に機能についてまとめたい。
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/textapp';
var dbName = 'textapp';
//データベースへ接続用関数
function connect(callback) {//関数化
MongoClient.connect(url, function(err, client) {//コールバック関数
//エラーの場合
if (err) {
console.log('データベース接続エラー', err);
//エラーじゃない場合
} else {
//接続成功
var db = client.db(dbName);
callback && callback(db);
}
});
}
module.exports = {
connect
}
接続する機能を関数化し、あとで使えるようにする。
登録&ログイン
ルーティング設定をする。
// 登録ページ
router.get('/regist', function(req, res, next) {
res.render('regist', {})
});
// ログインページ
router.get('/login', function(req, res, next) {
res.render('login', {})
});
登録ページのコードは以下になる。
<body>
<div class="container">
<div class="login-container">
<div class="form-box">
<form action="/users/regist" method="post">
<input type="text" name="username" value="" placeholder="ユーザ名">
<input type="password" name="password" value="" placeholder="パスワード">
<button class="btn btn-info btn-block login" type="submit">登録する</button>
</form>
<div>アカウントをお持ちの場合、<br><a href="/login">ログイン</a>してください。</div>
</div>
</div>
</div>
</body>
これにより、ユーザ名とパスワードは"/users/regist"
へ送信される。
// 登録
router.post('/regist', function(req, res, next) {
var data = {
username: req.body.username,
password: req.body.password
};
// データの接続
model.connect(function(db) {
//コレクションusersにデータ挿入する
db.collection('users').insertOne(data, function(err, ret) {
//登録失敗
if (err) {
console.log('登録失敗');
res.redirect('/regist');
} else {
//登録成功、ログインページへ
res.redirect('/login');
}
});
})
})
送信されてきた情報はdataに格納され、データベースに接続し、照らし合わせることで登録成功か失敗か。ちなみにmongoDBインストール時、MongoDB compassをインストールしていれば、それを開いて、connectを押すことでmongoDBへ接続でき、GUI画面で登録された情報は実際あるのかを確認できる。mongoDB compass参考
ログインページのコードは以下のようになる。
<body>
<div class="container">
<div class="login-container">
<div class="form-box">
<form action="/users/login" method="post">
<input name="username" type="text" placeholder="ユーザ名">
<input name="password" type="password" placeholder="パスワード">
<button class="btn btn-info btn-block login" type="submit">ログイン</button>
</form>
<div>アカウントをお持ちでない場合、<a href="/regist">作成</a>できます。</div>
</div>
</div>
</div>
</body>
これにより、ユーザ名とパスワードは"/users/login"
へ送信される。
// ログイン
router.post('/login', function(req, res, next) {
var data = {
username: req.body.username,
password: req.body.password
}
//データベースに接続する。
model.connect(function(db) {
//コレクションに同じデータがあるか、あればログイン成功。
db.collection('users').find(data).toArray(function(err, docs) {
if (err) {
//ログイン失敗→もう一回ログインページへ
res.redirect('/login');
}else {
//調べたdocsの結果が0以上であれば成功
if (docs.length > 0) {
// ログイン成功 session保存
req.session.username = data.username;//ユーザーネームをセッションに保存
res.redirect('/');
} else {
res.redirect('/login');
}
}
})
})
})
送信されてきた情報はdataに格納され、データベースに接続し、照らし合わせることでログイン成功か失敗か。失敗したらもう一度ログインページへ行く。また、上のコードでsessionを使用している。これはログイン状態を保存するため(毎回ログインするのはめんどくさいので)
sessionを使うためまずexpress-sessionをインストールする。textappフォルダ内で以下のコマンドを実行する。使い方はexpress-sessionドキュメント参照。
$ npm install express-session -S
最初に設定をする。
var session = require('express-session');
//セッション
app.use(session({
secret: 'sai textapp',//何でもよい
resave: false,
saveUninitialized: true,
cookie: { maxAge: 1000 * 60 * 20 } //cookie有効時間=ログイン有効期間
}))
ここでのログイン有効期間を20分とした。また上のログインが成功した場合ユーザ名をsessionに格納される。もしsessionにユーザ名がある場合、ログインせずにホームぺーズへ飛ぶことができるようになる。ユーザ名がニア場合、かつログインページと登録ページ以外ならば、ログインページへ戻る。これでログインしていない状態だとホームページは見れない。
// sessionの中身判定
app.get('*', function(req, res, next) {
var username = req.session.username;
//パスを判断したいので宣言
var path = req.path;
//ログインページと登録ページ以外で、ユーザ名なければログインページへ飛ぶ。
if (path != '/login' && path != '/regist') {
if (!username) {
res.redirect('/login');
}
}
next();
})
ログアウト
ヘッダーに投稿ボタンとログアウトボタンを配置する。
<li class="header_navi_item"><a href="/users/logout"><span>ログアウト</span></a></li>
ログアウトするには簡単で、sessionの中身を空っぽにしてlogin画面へ飛べばよい。
//ログアウト
router.get('/logout',function(req,res,next){
req.session.username = null;
res.redirect('/login');
})
記事投稿
ホームページに投稿するボタンを用意する。投稿画面/write
へ飛ぶ。
<li class="header_navi_item"><a href="/write"><span>投稿する</span></a></li>
write画面を作っていく。
<body>
<%- include('bar', {username: username}) %>
<div class="article">
<form action="/article/add" method="post">
<input type="text" name="title" placeholder="タイトル" value="">
<textarea name="content" class="xheditor" id="mytextarea"></textarea>
<input type="submit" value="投稿">
</form>
</div>
</body>
なお、ここでのbarはbar.ejsで、ヘッダーを作ります。ヘッダーは数画面同じものを使うので便利さを求めて別々にbar.ejsとして作り、includeによって呼び出して使う。この場合usernameを求めているので、routes/index.ejsの
router.get('/write', function(req, res, next) {})の中身にはusernameを取得しusernameを返す必要がある。そうするとusernameがbar(ヘッダー)のユーザ名のところに格納し、一番上の見た目のようにユーザ名が表示される。
ここで、投稿するためにリッチテキストエディターを実装したい。
リッチテキストエディタとは、HTMLを知らなくても文字、画像、表などをツールボタンを使って作成・編集することができるもの。実際にコピーしたものを投稿内容欄に張り付けても書式が残る。
→ブログ投稿をする際のエディタのようなもの
今回使用するのはTinyMCEというもの。公式ページの始め方参照はこちら
やや古いですがとても分かりやすいTinyMCE使い方記事はこちら
なお、ほかのリーチテキストエディタを使いたい場合、リッチテキストエディタ一覧を参考して、各自調べてください。
ドキュメント通りにコードを書く。バージョン古くなるかもしれないので必ずドキュメント参照推奨。ドキュメントのやり方だと、
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
http://
から始まって直接読み込むことができるので便利ですが、今回はTinyMCEを直接ダウンロードページからDownlord TinyMCE SDK now
をクリックし、ダウンロードして解凍して中身のファイルをtextapp/public/javascriptsの中にいれ、リンクは代わりにtinymce.min.jsを適切なパスで読み込む。今回の例では
javascripts/tinymce_5.10.3/tinymce/js/tinymce/
の中に存在する。
write.jsのheadタグ内をいじる。2つのscriptタグを追加した。
<head>
<title>記事作成</title>
<%- include head %>
<script src="javascripts/tinymce_5.10.3/tinymce/js/tinymce/tinymce.min.js" referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: 'textarea',
language: 'ja'
});
</script>
</head>
言語を日本語化にしたいので、TinyMCE言語パッケージページからjaを見つけ、ダウンロードする。解凍したlangsフォルダの「ja.js」を「tinymce/」にある「langsフォルダ」へ移動する。
うえのようにlanguage: 'ja'と記入すれば完成。
記事投稿するので、データベースに新しいコレクションを追加。
mongo shellで以下のコマンドを入力し、articlesコレクションを作る。
use textapp
db.createCollection('articles');
次は実際に記事書いたら、記事を投稿する機能を持つボタンを作る。ここで入力内容はformの/article/add
へ行く。ということで作成していく。
// 追加
router.post('/add', function(req, res, next) {
//データを受け取る
var data = {
title: req.body.title,//タイトル
content: req.body.content,//記事内容
username: req.session.username,//ユーザ名
id: Date.now()//時間
//データベースに接続し、データを挿入する
model.connect(function(db) {
db.collection('articles').insertOne(data, function(err, ret) {
if(err) {
console.log('文件发布失败', err)
//失敗、もう一回記事投稿ページ
res.redirect('/write')
} else {
//成功、ホームページへ
res.redirect('/')
}
})
})
}
})
正しく入っているかどうか、Mongo shellで確認するか、MongoDB compassで確認する。
記事表示(ホームページ)
まずroutes/index.jsの"/"
へ飛ぶ時の処理を編集する。
時間を扱いたいので、gitbashでtextapp内においてmomentをインストール。
npm install moment -S
公式ドキュメントはこちら
/* ホームページ*/
router.get('/', function(req, res, next) {
var username = req.session.username;
//データベース接続
model.connect(function(db) {
// すべての記事を調べる。
db.collection('articles').find().toArray(function(err, docs) {
var list = docs;
//ここでマップを使って、時間を表しているidを日付形式に変換し、timeと名付ける。
list.map(function(ele, index) {
ele['time'] = moment(ele.id).format('YYYY-MM-DD HH:mm:ss')
res.render('index', { username: username, data: list });
})
})
});
次に記事表示画面を作る。取得されたitemの中に必要な情報が入っている。
<% list.map(function(item,index){ %>
<div class="row">
<span><%= index+1 %></span>
<span><%= item.username %></span>
<span><%= item.title %></span>
<!-- 定義したtimeを使用している。-->
<span><%= item.time %></span>
<span>
<a href="">編集</a>
<a href="">削除</a>
</span>
</div>
<% }) %>
記事リストページ分け
記事が多い場合、ページ分けして1ページに何個記事表示できるかを設定。
routes/index.jsやviews/index.jsを編集する。
/* ホームページ*/
router.get('/', function(req, res, next) {
var username = req.session.username;
//フロント側で今は何ページ目にいるかデータを受け取る、なければ1
var page = req.query.page || 1;
var data = {
total: 0,//トータル何ページ必要か
curPage: page,//現在あるページ数
list:[]//今表示しているページの記事リスト
}
var pageSize = 2;//表示しているページに記事何個ひょうじするか
model.connect(function(db) {
// すべての記事を調べる。
db.collection('articles').find().toArray(function(err, docs) {
//全部の記事数÷1ぺ時に表示する記事数=トータル何ページ必要か
//Math.ceil() 関数は、引数として与えた数以上の最小の整数を返す
data.total = Math.ceil(docs.length / pageSize)
// 今のページの記事リストを調べる。
model.connect(function(db) {
// sort() limit() skip()
//降順で、一回に調べる記事数を限定(2)、スキップする個数(1ページ目なら(1-1)*2で0,スキップせず最初から2つ調べる)
db.collection('articles').find().sort({_id: -1}).limit(pageSize).skip((page-1)*pageSize).toArray(function(err, docs2) {
//時間変換
docs2.map(function(ele, index) {
ele['time'] = moment(ele.id).format('YYYY-MM-DD HH:mm:ss')
})
data.list = docs2
res.render('index', { username: username, data: data });
})
})
})
})
});
記事を分ける際、必要な情報は、
- total: トータルで何ページ必要か
- cuiPage: 現在あるページ数 (ここでは必要ないが後で削除機能のために使う)
- list: 今表示しているページの記事のリスト
- page: フロント側で今は何ページ目にいるかデータ
- pageSize: 1ページに表示したい記事数
であり、取得した記事数によって、
total =記事数÷pageSize(小数の場合大き目の整数に変換)
<body>
<%- include('bar', {username}) %>
<div class="list">
<!-- ページ分け、何ページ目 -->
<div class="pages">
<% for(let i=1; i<=data.total; i++) { %>
<!-- ここでクリックすると今いる何ページ目かが"/"にわたり、そのページ内容を表示したい-->
<a class="pages_style" href="/?page=<%= i %>"><%= i %></a>
<% } %>
</div>
<div class="row">
<span>順番</span>
<span>作者</span>
<span>タイトル</span>
<span>公開日</span>
<span>
<i class="fa-solid fa-pen-to-square"></i>
</span>
</div>
<!-- 記事リスト -->
<% data.list.map(function(item,index){ %>
<div class="row">
<span><%= index+1 %></span>
<span><%= item.username %></span>
<span><%= item.title %></span>
<span><%= item.time %></span>
<span>
<a href="">編集</a>
<a href="">削除</a>
</span>
</div>
<% }) %>
</div>
</body>
for文でdata.totalを使用し、実際のページ数を表示。また、ページボタンに今のいるページ何番目かを意味するpageを"/"
に渡しているので、この情報を使って表示すべき記事を選出し、data.listに格納される。
記事削除
views/index.jsの削除のところを下のように直す。
削除するために必要な情報は、記事のidはもちろん、もう1つは今何ページ目にいるかという、pageが必要。なお、?id=<%=item.id%>&page=<%=data.curPage%>のところ、
?の後ろにはURLパラメータが来ていて、この値を行先に渡すイメージ。
<a href="/article/delete?id=<%=item.id%>&page=<%=data.curPage%>">削除</a>
routes/article.jsも編集。
// 記事削除
router.get('/delete', function(req, res, next) {
var id = parseInt(req.query.id)
var page = req.query.page
//接続
model.connect(function(db) {
//idで調べる
db.collection('articles').deleteOne({id: id}, function(err, ret) {
if (err) {
console.log('削除失敗');
} else {
console.log('削除成功');
}
//リダイレクトする
res.redirect('/?page='+page);
})
})
})
なおこの状態では、たとえ削除したページに記事が1つもなくても、表示できるので、不適切である。これを直すため、routes/index.jsに判定条件を追加する。
/* ホームページ*/
router.get('/', function(req, res, next) {
var username = req.session.username;
//フロント側で今は何ページ目にいるかデータを受け取る、なければ1
var page = req.query.page || 1;
var data = {
total: 0,//トータル何ページ必要か
curPage: page,//現在あるページ数
list:[]//今表示しているページの記事リスト
}
var pageSize = 2;//表示しているページに記事何個ひょうじするか
model.connect(function(db) {
// すべての記事を調べる。
db.collection('articles').find().toArray(function(err, docs) {
//全部の記事数÷1ぺ時に表示する記事数=トータル何ページ必要か
//Math.ceil() 関数は、引数として与えた数以上の最小の整数を返す
data.total = Math.ceil(docs.length / pageSize)
// 今のページの記事リストを調べる。
model.connect(function(db) {
// sort() limit() skip()
//降順で、一回に調べる記事数を限定(2)、スキップする個数(1ページ目なら(1-1)*2で0,スキップせず最初から2つ調べる)
db.collection('articles').find().sort({_id: -1}).limit(pageSize).skip((page-1)*pageSize).toArray(function(err, docs2) {
//記事がなければ
if (docs2.length == 0) {
//前のページに戻る、最小1
res.redirect('/?page='+((page-1) || 1))
} else {
//記事があれば、時間の処理をする。
docs2.map(function(ele, index) {
ele['time'] = moment(ele.id).format('YYYY-MM-DD HH:mm:ss')
})
data.list = docs2
}
res.render('index', { username: username, data: data });
})
})
})
})
});
記事編集
writeへ飛ぶ。同じくidとcurPageが必要。
<a href="/write?id=<%=item.id%>&page=<%=data.curPage%>">編集</a>
router.get('/write', function(req, res, next) {})は以下のようになる。
// 投稿&編集ページ
router.get('/write', function(req, res, next) {
var username = req.session.username || ''
var id = parseInt(req.query.id)
var page = req.query.page
var item = {
title: '',
content: ''
}
if (id) { // idがあれば編集
model.connect(function(db) {
db.collection('articles').findOne({id: id} , function(err, docs) {
if (err) {
console.log('失败')
} else {
item = docs
item['page'] = page
res.render('write', {username: username, item: item})
}
})
})
} else { // idがなければ追加
res.render('write', {username: username, item: item})
}
})
また、write画面も編集する。
<body>
<%- include('bar', {username: username}) %>
<div class="article">
<form action="/article/add" method="post">
<input type="hidden" name="id" value="<%- item.id %>">
<input type="hidden" name="page" value="<%- item.page %>">
<input type="text" name="title" placeholder="タイトル" value="<%= item.title %>">
<textarea name="content" class="xheditor" id="mytextarea"><%- item.content %></textarea>
<% if (item.id) { %>
<input type="submit" value="編集">
<%} else {%>
<input type="submit" value="投稿">
<%}%>
</form>
</div>
</body>
ボタンもif文でidがあれば編集、なければ投稿と表示。
また、編集をするためにpageとidを渡さなければならない。
編集成功したらpageに飛びたいので。
<input type="hidden" name="id" value="<%- item.id %>">
<input type="hidden" name="page" value="<%- item.page %>">
hidenを使って見えなくし、配置する。
/article/add
のところも編集する。同じくidで編集する。
// 追加、編集
router.post('/add', function(req, res, next) {
var id = parseInt(req.body.id)
if (id) { //編集
var page = req.body.page
var title = req.body.title
var content = req.body.content
model.connect(function(db) {
db.collection('articles').updateOne({id: id}, {$set: {
title: title,
content: content
}}, function(err, ret) {
if (err) {
console.log('編集失敗', err)
} else {
console.log('編集成功')
res.redirect('/?page='+page)
}
})
})
} else { //追加
var data = {
title: req.body.title,
content: req.body.content,
username: req.session.username,
id: Date.now()
}
model.connect(function(db) {
db.collection('articles').insertOne(data, function(err, ret) {
if(err) {
console.log('失败', err)
res.redirect('/write')
} else {
res.redirect('/')
}
})
})
}
})
記事表示
タイトルのところに行先を設定。
<span><a href="/detail?id=<%=item.id%>"><%= item.title %></a></span>
記事表示ページを作成する。
<!DOCTYPE html>
<html lang="ja">
<head>
<title><%=item.title%></title>
<%- include head %>
</head>
<body>
<%- include('bar', {username: username}) %>
<div class="detail">
<div class="title"><%=item.title%></div>
<div class='desc'>
<span>作者:<%=item.username%></span>
<span>投稿日:<%=item.time%></span>
</div>
<div class="content"><%-item.content%></div>
</div>
</body>
</html>
routes/index.jsにもコードを追加する。
// 記事詳細ページ
router.get('/detail', function(req, res, next) {
var id = parseInt(req.query.id)
var username = req.session.username || ''
model.connect(function(db) {
db.collection('articles').findOne({id: id}, function(err, docs) {
if (err) {
console.log('失败', err)
} else {
var item = docs
item['time'] = moment(item.id).format('YYYY-MM-DD HH:mm:ss')
res.render('detail', {item: item, username: username})
}
})
})
})
これでタイトルを押したら、該当記事の詳細を確認できる。
その他
このままだと、実はほかの人でも他人の記事を編集&削除できる。これはまずいので、変えていく。やり方は簡単、以下のように修正すればいい。
<!-- 記事リスト -->
<% data.list.map(function(item,index){ %>
<div class="row">
<span><%= index+1 %></span>
<span><%= item.username %></span>
<span><a href="/detail?id=<%=item.id%>"><%= item.title %></a></span>
<span><%= item.time %></span>
<span>
<% if (item.username===username) { %>
<a href="/write?id=<%=item.id%>&page=<%=data.curPage%>">編集</a>
<a href="/article/delete?id=<%=item.id%>&page=<%=data.curPage%>">削除</a>
<%} else {%>
<span class="grey">編集</span>
<span class="grey">編集</span>
<%}%>
</span>
</div>
<% }) %>
ここではif文を使って判定している。usernameはsessionから取得した今ログイン中のユーザ名、item.usernameとはそれぞれの記事の作者名である。一致しなければ編集&削除ができない。
デプロイ(公開)
まだ未公開ですが、EC2で公開したいと思っていて、以下の記事参考になりそうなのでいったんメモしておきます。
ec2
【AWS】EC2とは?概要から使い方までざっくり解説(実践あり)
node.js
[AWS] 手順に沿った画像付きでAmazon EC2にNode.js, Express環境の構築する
チュートリアル: Amazon EC2 インスタンスでの Node.js のセットアップ
AWS EC2でNodeを動作させる
mongodb
MongoDB CommunityEditionをAmazonLinuxにインストールします
途中までやっていた。コマンドメモ↓↓
$ ssh -i textapp-key.pem ec2-user@18.183.176.255
$ ssh -i textapp-key.pem ec2-user@18.183.176.255
$ sudo yum update
$ sudo yum install git gcc-c++ make openssl-devel
$ nvm install v16.14.0
$ nvm alias default v16.14.0
$ npm install express-generator -g
npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
$ npm update -g mkdirp
$ npm install -g npm@8.5.3
$ git clone https://github.com/akikisai/Article-management-app.git
$ ls -a
$ cd Article-management-app/
$ npm install
$ grep ^NAME /etc/*release
/etc/os-release:NAME="Amazon Linux"
$ cd /etc/yum.repos.d
$ sudo touch mongo-org-5.0.repo
$ sudo su
# vi mongo-org-5.0.repo
[mongodb-org-5.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/5.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-5.0.asc
:wq!
# sudo yum install -y mongodb-org
exclude=mongodb-org,mongodb-org-database,mongodb-org-server,mongodb-org-shell,mongodb-org-mongos,mongodb-org-tools
# ps --no-headers -o comm 1
systemd
# sudo systemctl start mongod
# sudo systemctl status mongod
Active: active (running) since Sat 2022-03-05 12:30:03 UTC; 29s ago
$ mongosh
>use textapp
>db.createCollection('users');
>db.createCollection('articles');
$ cd Article-management-app/
node ./bin/www
躓いた。。もう少しいろいろ試したい。
問題点
今回は機能を作ってみるだけにしましたが、まだしっかりとしたエラー処理を書いていなく(ユーザ名判定など) マークダウンにも対応させたいと思っていて、全然新しい機能を追加する余地はあるが、今回は一旦締め切りにする。