React + Node + Mongo +Webpack寫一個(gè)簡(jiǎn)單的Blog網(wǎng)站

用到的技術(shù):React Node Webpack material-ui mongo

github地址:https://github.com/shenjiajun53/HiBlog
喜歡請(qǐng)給個(gè)star?闷4媪А!
推薦兩個(gè)工具:https://app.astralapp.com/dashboard 這個(gè)網(wǎng)站可以用來管理github上的star

另一個(gè)叫 Octotree 是Chrome應(yīng)用恋脚,可以看到github上的項(xiàng)目結(jié)構(gòu)恋腕,跟IDE一樣

我是一名Android開發(fā)抹锄,雖然在互聯(lián)網(wǎng)公司,但是感覺自己的工作根本就是軟件行業(yè)的工作荠藤。
想想對(duì)服務(wù)端伙单,前端都不了解真是挺無(wú)知的。
之前看同事有自己的博客站哈肖,百度了下吻育,發(fā)現(xiàn)要做那種個(gè)人網(wǎng)站真是很簡(jiǎn)單,只不過那根本就是個(gè)靜態(tài)網(wǎng)站淤井,太辣雞布疼,所以我決定自己擼個(gè)博客網(wǎng)站。

主頁(yè)

home_page.png

注冊(cè)頁(yè)

register_page.png

下面就是技術(shù)選型啦:

前端:

要用就用潮的币狠,三個(gè)著名框架Angular游两,React,Vue
Angular聽說1和2完全不兼容漩绵,最討厭這種對(duì)開發(fā)人員不負(fù)責(zé)的框架了贱案,不考慮
Vue的語(yǔ)法更像常規(guī)的前端開發(fā),React默認(rèn)支持es6止吐,風(fēng)格跟Android更像宝踪,尤其跟Android的DataBinding很像。
另一方面es6很像Java碍扔,我肯定使用es6開發(fā)的瘩燥,我更喜歡面向?qū)ο蟆ue當(dāng)然也可以用es6蕴忆,但我懶得鼓搗了颤芬,更重要的ReactNative可比Weex火多了。哈哈套鹅,所以前端我就選擇React了。
真正的前端開發(fā)應(yīng)該更喜歡Vue吧汰具,文檔都有中文的卓鹿。

后端:

雖然我是做Android的,但是遙想兩年前第一次接觸JavaEE的時(shí)候真是被惡心到了留荔,不考慮
python沒有花括號(hào)吟孙,知乎上都嘲笑寫python要用游標(biāo)卡尺澜倦,不考慮
PHP開發(fā)比Java更快,而且現(xiàn)在快跟Java平分秋色了吧杰妓,可以考慮藻治。
Node技術(shù)還是挺新的,各種文章資料會(huì)比較少巷挥,坑也可能比較多桩卵。但我真是不高興再學(xué)一門語(yǔ)言了,所以哈哈倍宾,就選Node了雏节。

運(yùn)行

1.git clone
2.安裝mongo,然后在安裝目錄下新建文件夾高职,比如“D:\data\db”钩乍,然后打開“D:\MongoDB\Server\3.4\bin\mongod.exe”開啟服務(wù),會(huì)有個(gè)命令行窗口保持運(yùn)行
3.建議安裝一個(gè)mongo可視化工具怔锌,Robomongo寥粹,默認(rèn)連接localhost:27017,能連接上就說明好了
4.進(jìn)入項(xiàng)目目錄下埃元,執(zhí)行命令

npm install

安裝相關(guān)依賴庫(kù)
5.執(zhí)行

node server.js

開啟服務(wù)涝涤。
或者,比如我用的Webstorm亚情,可以點(diǎn)擊左下角npm按鈕妄痪,點(diǎn)擊start-dev-serpervisor或者點(diǎn)擊start-dev-nodemon,都可以

webstorm.png

6.打開瀏覽器,輸入 localhost:5006

下面開始:

我對(duì)前后端幾乎零基礎(chǔ)楞件,之前有看過ReactNative衫生,順便看了下React。
所以寫的代碼在內(nèi)行眼里可能很丟人土浸,哈哈

第一步:

安裝node罪针,新建個(gè)文件夾,HiBlog
命令行:

cd HiBlog

初始化:

npm init

生成package.json文件
然后安裝各種需要的包黄伊,比如express--node框架泪酱,webpack--打包工具

npm i express  --save;npm i webpack --save

然后這兩個(gè)就下載好了,在node_module文件夾下还最,引用也自動(dòng)添加到package.json文件里了
或者package.json文件直接復(fù)制的別人的墓阀,里面有內(nèi)容了,

npm i

把package里所有引用都下載到node_module下拓轻。
跟Android的依賴很像啊

我的module引用

{
  "name": "HiBlog",
  "version": "0.1.0",
  "private": true,
  "engines": {
    "node": "^7.4.0",
    "npm": ">= 3.x.x"
  },
  "devDependencies": {
    "concurrently": "^3.1.0",
    "nodemon": "^1.11.0",                                     //node監(jiān)聽工具斯撮,改動(dòng)代碼自動(dòng)重啟服務(wù)
    "supervisor": "^0.12.0",                                   //跟上面一樣的,用一個(gè)就行扶叉,反正我都加了
  },
  "dependencies": {
    "antd": "^2.6.4",                                         //螞蟻金服的UI框架勿锅,項(xiàng)目里沒用帕膜,哈哈
    "babel-core": "^6.22.1",
    "babel-loader": "^6.2.10",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-react": "^6.22.0",
    "body-parser": "^1.16.0",
    "config-lite": "^1.5.0",
    "connect-flash": "^0.1.1",
    "connect-mongo": "^1.3.2",
    "cookie-parser": "^1.4.3",
    "css-loader": "^0.26.1",
    "ejs": "^2.5.5",
    "express": "^4.14.1",
    "express-formidable": "^1.0.0",
    "express-session": "^1.15.0",
    "express-winston": "^2.1.3",
    "jsx-loader": "^0.13.2",
    "marked": "^0.3.6",
    "material-ui": "^0.16.7",                                      //UI框架,項(xiàng)目里主要用的就是這個(gè)
    "moment": "^2.17.1",
    "mongoose": "^4.8.1",                                     //數(shù)據(jù)庫(kù)框架
    "multer": "^1.3.0",
    "objectid-to-timestamp": "^1.3.0",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-router": "^3.0.2",
    "react-tap-event-plugin": "^2.0.1",
    "roboto": "^0.8.2",
    "sha1": "^1.1.1",
    "style-loader": "^0.13.1",
    "webpack": "^1.14.0",
    "winston": "^2.3.1"
  },
  "scripts": {
    "start": "node server.js",                                          //啟動(dòng)服務(wù)
    "start-supervisor": "supervisor --harmony server",        //啟動(dòng)服務(wù)    代碼有變動(dòng)就重啟
    "start-nodemon": "nodemon server.js",                    //啟動(dòng)服務(wù)       代碼有變動(dòng)就重啟
    "build": "webpack --watch",                                   //打包React代碼溢十, --watch代表代碼有變動(dòng)就重新打包
    "start-dev": "concurrently \"npm run start\" \"npm run build\"",
    "start-dev-supervisor": "concurrently \"npm run start-supervisor\" \"npm run build\"",
    "start-dev-nodemon": "concurrently \"npm run start-nodemon\" \"npm run build\""
  }
}

看下我的目錄結(jié)構(gòu)

2017-02-18.png

看下我的github頁(yè)面垮刹,右邊就是我在最上面介紹的github插件,工欲善其事必先利其器张弛。

新建文件webpack.config.js荒典,webpack工具會(huì)識(shí)別到這個(gè)文件里的腳本,然后把React代碼打包乌庶,很重要种蝶,不然不管是React的JSX或者ES6,瀏覽器都讀不懂瞒大。

新建文件夾views螃征,里面是前端代碼
新建文件夾routes,里面放路由代碼透敌,因?yàn)槲覀冇玫腞eact盯滚,所以這個(gè)網(wǎng)站就是所謂的單頁(yè)網(wǎng)站,One Page Website酗电∑桥海看views下面只有一個(gè)index.html。
這個(gè)HTML就是個(gè)空殼撵术,真正的網(wǎng)頁(yè)都是有js代碼生成的背率,不管是哪個(gè)頁(yè)面,都依托這個(gè)HTML嫩与。所以這里和常規(guī)網(wǎng)頁(yè)不通寝姿,網(wǎng)頁(yè)不是由服務(wù)器渲染的一個(gè)個(gè)HTML。網(wǎng)站的工作方式更像APP划滋,通過api實(shí)現(xiàn)網(wǎng)頁(yè)內(nèi)容變動(dòng)饵筑。前后端分離才是人性化的開發(fā)方式,不是嗎处坪?

文件夾config根资,里面放一些設(shè)置

最重要的server.js

/**
 * Created by shenjj on 2017/1/23.
 */
let express = require('express');
let app = express();
let path = require('path');
let ejs = require('ejs');
let bodyParser = require("body-parser");
let MongoUtil = require("./server/lib/MongoUtil");
let session = require('express-session');
let MongoStore = require('connect-mongo')(session);
let cookieParser=require("cookie-parser");
let config = require('config-lite');
let flash = require('connect-flash');

let homeRouter = require('./routes/HomePageRouter');
let userRouter = require('./routes/userInfo');
// let signRouter = require("./server/signUp").signUp;
// let DealSignUp = require("./server/DealSignUp");
let RouterManager = require("./routes/RouterManager");

// 設(shè)置模板目錄
app.set('views', './views');

// 設(shè)置模板引擎為 ejs
app.set('view engine', 'html');
app.engine('html', ejs.renderFile);

// app.use配置
app.use('/output', express.static(path.join(__dirname, '/output')));
//app.use('/views', express.static(path.join(__dirname, '/views')));
app.use('/uploadFiles', express.static(path.join(__dirname, '/uploadFiles')));

...
...

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

// app.use('/', homeRouter);
app.use('/users', userRouter);

let routerManager = new RouterManager(app);
routerManager.startRouters();


app.get('*', function (request, response) {
    response.sendFile(path.resolve(__dirname, 'views', 'index.html'))
});

app.listen(process.env.PORT || 5006);

console.log("url=" + process.env.PORT);

這里開始就是真的node代碼里
設(shè)置模版目錄在views下面,其實(shí)就是那個(gè)index.html
這是模版引擎ejs同窘,用來渲染成html玄帕,(有兩個(gè)主流引擎ejs和jade,ejs和html一毛一樣想邦,所以我推薦這個(gè)桨仿,jade雖然省代碼,但是跟python一樣案狠,太隨便了)
另外我不需要用ejs的功能服傍,所以我直接設(shè)置成HTML了。

app.use('/output', express.static(path.join(__dirname, '/output')));
app.use('/uploadFiles', express.static(path.join(__dirname, '/uploadFiles')));
用來指定打包后的js代碼骂铁,在output目錄下吹零,這個(gè)是在wenpack.config里設(shè)置的
uploadFiles是js代碼里引用的圖片,空目錄拉庵,里面的圖片是用戶上傳的灿椅。

RouterManager是我寫的Router管理類,從風(fēng)格也能看出我就是比較習(xí)慣Java钞支,還是面向?qū)ο笫娣S迹m然代碼量大一點(diǎn)。
routerManater把a(bǔ)pp傳進(jìn)去

最后是端口號(hào)烁挟,默認(rèn)5006

RouterManager里:

...
        this.app.use("/", new HomePageRouter().getRouter());
        this.app.use("/api", new UserRouter().getRouter());
        this.app.use("/api", new BlogRouter().getRouter());
...

HomePageRouter里:

        router.get('/', function (req, res) {
            console.log("homepage on render");
            res.render('index');
            // res.render('');
            // res.redirect("/SignUp");
        });

所以就是婴洼,直接在瀏覽器輸入localhost:5006,會(huì)跳轉(zhuǎn)到主頁(yè)
如果輸入localhost:5006/api/xxx撼嗓,會(huì)調(diào)起userRouter或者blogRouter里的接口柬采,看那個(gè)匹配了

下面是部分前端代碼

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            hasLogin: false,
            user: null
        }
    }

    componentWillMount() {
        let url = "/api/getUserInfo";
        fetch(url, {
            method: "post",
            credentials: 'include'     //很重要,設(shè)置session,cookie可用
        }).then(
            (response) => {
                return response.json();
            }
        ).then(
            (json) => {
                console.log(JSON.stringify(json));
                if (json.result) {
                    this.setState({
                        hasLogin: json.result.hasLogin,
                        user: json.result.user
                    });
                }
                // console.log("state=" + this.state.hasLogin);
            }
        ).catch(
            (ex) => {
                console.error('parsing failed', ex);
            });
    }

    render() {
        console.log('app render');
        // console.log('chileren=' + this.props.children.name);
        return (
            <MuiThemeProvider>
                <div>

                    <TopBar hasLogin={this.state.hasLogin} user={this.state.user}/>
                    {React.cloneElement(this.props.children, {user: this.state.user})}
                </div>
            </MuiThemeProvider>
        );
    }
}

render(
    <Router history={browserHistory}>
        <Route path="/" component={App}>
            <IndexRoute component={Home}/>
            <Route path="SignUp" component={SignUp}/>
            <Route path="SignIn" component={SignIn}/>
            <Route path="UserCenter" component={UserCenter}/>
            <Route path="MyFollow" component={MyFollow}/>
            <Route path="WriteBlog" component={WriteBlog}/>
            <Route path="BlogDetail/:blogId" component={BlogDetail}/>
            <Route path="Settings" component={Settings}/>
            <Route path="Favorites" component={Favorites}/>
            <Route path="MyBlogs" component={MyBlogs}/>
        </Route>
    </Router>
    ,
    document.getElementById('root')
)

頁(yè)面跳轉(zhuǎn)完全由前端控制且警,用Rooter類粉捻,APP是整個(gè)網(wǎng)頁(yè)的父布局鸿竖。在APP渲染完成后獲取user信息瓷炮,this.props.children是當(dāng)前頁(yè)面,可以clone一個(gè)ReactComponent速缨,并設(shè)置props杏头。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盈包,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子大州,更是在濱河造成了極大的恐慌续语,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厦画,死亡現(xiàn)場(chǎng)離奇詭異疮茄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)根暑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門力试,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人排嫌,你說我怎么就攤上這事畸裳。” “怎么了淳地?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵怖糊,是天一觀的道長(zhǎng)帅容。 經(jīng)常有香客問我,道長(zhǎng)伍伤,這世上最難降的妖魔是什么并徘? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮扰魂,結(jié)果婚禮上麦乞,老公的妹妹穿的比我還像新娘。我一直安慰自己劝评,他們只是感情好姐直,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蒋畜,像睡著了一般声畏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上百侧,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天砰识,我揣著相機(jī)與錄音,去河邊找鬼佣渴。 笑死辫狼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辛润。 我是一名探鬼主播膨处,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼砂竖!你這毒婦竟也來了真椿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乎澄,失蹤者是張志新(化名)和其女友劉穎突硝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體置济,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡解恰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浙于。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片护盈。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖羞酗,靈堂內(nèi)的尸體忽然破棺而出腐宋,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布胸竞,位于F島的核電站欺嗤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏撤师。R本人自食惡果不足惜剂府,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剃盾。 院中可真熱鬧,春花似錦淤袜、人聲如沸痒谴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)积蔚。三九已至,卻和暖如春烦周,著一層夾襖步出監(jiān)牢的瞬間尽爆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工读慎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漱贱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓夭委,卻偏偏與公主長(zhǎng)得像幅狮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子株灸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容