成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

個(gè)人博客主頁(yè)搭建隨筆

cnio / 434人閱讀

摘要:博主目前的這個(gè)項(xiàng)目還不算很大,模塊依賴簡(jiǎn)單,但期望完成諸如版本號(hào)替換,壓縮代碼,合并文件,發(fā)布到服務(wù)器等和模塊化關(guān)系不大的工作,所以使用了。同時(shí),對(duì)和附加緩存,配合和版本號(hào)實(shí)現(xiàn)服務(wù)器更新,這一部分其實(shí)已經(jīng)幫我們實(shí)現(xiàn)好了。

經(jīng)常在各種論壇、博客還有 github 上活躍的朋友不難發(fā)現(xiàn),許多大牛都有自己的網(wǎng)站,也多以博客為主。博主作為一個(gè)立志前端的大白,難道不應(yīng)該和大牛學(xué)習(xí)么?

說干就干,前端部分和 web 開發(fā)博主做了很多學(xué)習(xí)和總結(jié),不少也寫成了博客。對(duì)于后端,博主不敢說完全沒有經(jīng)驗(yàn),但接觸的也都比較簡(jiǎn)單。于是乎,博主去年六月底開始看 Node 和 Express,利用空閑時(shí)間做了自己的博客,現(xiàn)階段還有許多不足,需要后續(xù)不斷改進(jìn)。不過這不妨礙博主先總結(jié)一下自己的感受。

UI設(shè)計(jì) 和 架構(gòu)設(shè)計(jì)

博主深刻的感受到自己并沒有什么藝術(shù)細(xì)胞,只能去看各種設(shè)計(jì)稿刺激一下自己的神經(jīng),比如 Dribbble、water Chen UI、 千庫(kù)、 DotSpin、LogoSpire、Tencent ISUX 等等。其實(shí)不止這些,比較我看見的鏈接就會(huì)點(diǎn)進(jìn)去,不知道點(diǎn)了多少,然后就這么憋出了一份入門級(jí)都算不上的 UI 設(shè)計(jì)圖(不要笑,要指點(diǎn))。

對(duì),就是這么簡(jiǎn)單粗暴,連 ps 都沒用!

架構(gòu)設(shè)計(jì)部分也沒有太深入的知識(shí),簡(jiǎn)單的 MVC 結(jié)構(gòu),對(duì)于架構(gòu)入門來說再適合不過了,即使現(xiàn)在的前端,有了 MV 結(jié)構(gòu)的 React,MVVM 的 Angular 和 vue。架構(gòu)如下圖,這次終于用到 ps,其實(shí)找個(gè) word 就可以畫的。


(還是這句話:不要笑,要指點(diǎn))

框架選型

由于自己還沒有看到Angular、vue、React這寫流行的框架,前端樣式的實(shí)現(xiàn)還是選擇使用了 Bootstrap 和 Sass。而結(jié)構(gòu)選擇了 jade 模板引擎。這里會(huì)有以下幾個(gè)問題:

為什么使用 Bootstrap ?

這個(gè)不復(fù)雜,畢竟我希望實(shí)現(xiàn)兼容移動(dòng)端和 PC 端的響應(yīng)式頁(yè)面,所以我只能說,媒體查詢是利器,Bootstrap 是別無可選。

為什么我使用 Sass ?

寫習(xí)慣了 css 就不太習(xí)慣 Scss 的縮進(jìn),畢竟還有 less 和 Sass, 而選擇了 Sass 的原因如下:

Sass有一些成熟穩(wěn)定的框架,如是Compass,F(xiàn)oundation,側(cè)面說明 Sass 比 Less 更好吧。

還有一個(gè)原因是國(guó)外討論Sass的同行要多于Less,使用 Sass 的也更多一些。

Sass有更清晰的語法,像一門編程語言一樣,不像 Less 的混合大法使用起來感覺不舒服。

如果說 Sass 有么不好,那就是它還是建立在 ruby 上,有點(diǎn)不直接,比較麻煩。

為何使用 jade ?

這個(gè)不需要太多理由,比 html 簡(jiǎn)潔,還比 html 強(qiáng)大!比起其他模板引擎,他又是專門為 html 服務(wù)的。和 EJS 相比,jade 支持模板繼承,而 EJS 不支持。
其實(shí)我是個(gè)人開發(fā),如果是團(tuán)隊(duì)開發(fā),我還是覺得 EJS 會(huì)更好,可能是博主適應(yīng)了挖坑的寫法,用 html 會(huì)對(duì)前后端開發(fā)都方便許多。而且 jade 的縮進(jìn)風(fēng)格跨 IDE 會(huì)不方便。當(dāng)然還有其他的模板引擎,比如 swig,對(duì)博主來說完全是不習(xí)慣 Django 的風(fēng)格。

當(dāng)然這里還有個(gè)其它原因:Express 默認(rèn) jade !!!

后端開發(fā)使用了 Nodejs + Express + MongoDB, 不得不說這個(gè)組合的資料真的很多,學(xué)習(xí)起來方便一些。這里沒有為什么,就是想學(xué) Node,而不是世界上最美的語言,畢竟有 js 基礎(chǔ)嘛。

為何使用 MongoDB ?

說實(shí)在的,這是博主第一次接觸并使用非關(guān)系數(shù)據(jù)庫(kù),突然發(fā)現(xiàn)很喜歡它。之前使用的更多的是 MySQL。畢竟博客系統(tǒng),存儲(chǔ)的數(shù)據(jù)是文章,所以關(guān)系數(shù)據(jù)庫(kù)定義數(shù)據(jù)類型實(shí)在是個(gè)坑,分配大了浪費(fèi),分配小了怎么寫東西!當(dāng)然,還有其他的問題。由于我發(fā)現(xiàn)許多文章都使用 MongoDB,其實(shí)也就沒有再猶豫。這里想要說的還是使用它的感受,一句話概括:JSON 的存儲(chǔ)方式真的是既直接,又爽快!

為何使用 Express ?

我們都知道,Express 其實(shí)不能說是對(duì) Node 的二次開發(fā),而是一個(gè)擴(kuò)展。博主開始學(xué)習(xí)前端,從基礎(chǔ)做起來是不會(huì)有錯(cuò)的,如果你希望快速的開發(fā),僅僅當(dāng)它是個(gè)工具,那用 sail 會(huì)省事很多,再配合腳手架,事半功倍。當(dāng)然 sail 除了官方文檔好像也沒啥別的可以學(xué)習(xí)了,這個(gè)......
其實(shí) sail 發(fā)展不起來也是有原因的:

當(dāng)然,如果有時(shí)間,博主倒還想學(xué)習(xí)一下,koa 和 hapi

最后一個(gè)選擇就是項(xiàng)目構(gòu)建工具了,這里可以直接解釋我為何使用了 Gulp

為什么選擇 Gulp ?

其實(shí)這里可選的常用構(gòu)建工具還有 webpack 和 grunt。gulp 和 webpack 其實(shí)各有優(yōu)勢(shì),比如 gulp 任務(wù)定義和管理,Webpack 做不到,Webpack 基于模塊的依賴構(gòu)建。gulp 也做不好。而 grunt 的確是比較笨重復(fù)雜,明顯能看出來現(xiàn)在用的已經(jīng)比較少了。
其實(shí) gulp 和 webpack 使用的感覺也不一樣,gulp 是在寫一個(gè)個(gè)的任務(wù),而 webpack 是在寫一個(gè)配置文件,注意我說的是感覺。
從他們的核心功能來講,Gulp 定義任務(wù)和阻止,基于文件流的構(gòu)建。而 webpack 按照模塊的依賴構(gòu)建目標(biāo)文件,具有支持不同模塊的 loader 體系。如果要用 Webpack,請(qǐng)確保項(xiàng)目模塊化,模塊之間充分依賴。除此之外的構(gòu)建工作,都應(yīng)該交給 gulp 繼續(xù)完成。博主目前的這個(gè)項(xiàng)目還不算很大,模塊依賴簡(jiǎn)單,但期望完成諸如版本號(hào)替換,壓縮代碼,合并文件,發(fā)布到服務(wù)器等和模塊化關(guān)系不大的工作,所以使用了 gulp。

博主使用 Gulp 也是自己的學(xué)習(xí)過程,正是因?yàn)?Gulp 和 Webpack 各有優(yōu)缺點(diǎn),下一步博主還是計(jì)劃能用 Webpack 重新構(gòu)建一下這個(gè)項(xiàng)目,親自感受一下它們的魅力。

項(xiàng)目的整體流程

確定功能,根據(jù)需求選擇合適的框架和工具

設(shè)計(jì)界面、架構(gòu)、數(shù)據(jù)庫(kù)的模式

構(gòu)建 express 的服務(wù)器框架和目錄結(jié)構(gòu)

設(shè)計(jì) gulp task 和 livereload

編寫頁(yè)面

測(cè)試功能模塊

做必要的性能優(yōu)化

遇到的難點(diǎn)和坑

總結(jié)這個(gè)問題,博主真的感覺好為難。以博主的性格,做之前會(huì)覺得:“這個(gè)東西沒做過,好難,但查查資料今天上午一定能做出來”,做完了以后總覺得:“沒想到挺簡(jiǎn)單的?。?!”所以說呢,現(xiàn)在做完了,感覺都不難了。

其實(shí)最難的應(yīng)該屬于快速學(xué)習(xí)并使用這些工具,快速查找并解決問題。博主用了一個(gè)月的每個(gè)晚上和周末學(xué)習(xí)了 Nodejs + Express + MongoDB + Gulp, 做了這個(gè)博客,可以說大致理解他們的開發(fā)邏輯,結(jié)構(gòu),和基本使用方法。很多難以解決的問題,也無非是 google、知乎、github。

登錄功能實(shí)現(xiàn)

登錄功能,利用了 passport 和 validator 組件實(shí)現(xiàn),首先是驗(yàn)證登錄,在 user model 中實(shí)現(xiàn)方法 verifyPassword

UserSchema.methods.verifyPassword = function(password){
  return password === this.password;
}

而對(duì)于需要驗(yàn)證的頁(yè)面,在 user 的 controller 中實(shí)現(xiàn)了 中間件:

var needLogin = function(req, res, next){
  if(req.user){
    next();
  } else {
    req.flash("error", "請(qǐng)先登錄");
    res.redirect("/admin/users/login");
  }
}
module.exports.requireLogin = needLogin;

對(duì)于與 validator 在 express.js 中按要求添加 use 就可以啦。

app.use(validator({
    errorFormatter: function(param, msg, value) {
        var namespace = param.split(".")
        , root    = namespace.shift()
        , formParam = root;

      while(namespace.length) {
        formParam += "[" + namespace.shift() + "]";
      }
      return {
        param : formParam,
        msg   : msg,
        value : value
      };
    }
  }));

加密使用了 md5, 這個(gè)不多說了。還有一點(diǎn)就是登錄狀態(tài)驗(yàn)證:在服務(wù)器端,登錄狀態(tài)被存儲(chǔ)在數(shù)據(jù)庫(kù)的 sessions 集合中,通過 passport 和 express-session 實(shí)現(xiàn):

app.use(session({
    secret: "nodeblog",
    resave: false,
    saveUnitialized: true,
    cookie: {secure: false},
    store: new MongoStore({ mongooseConnection: connection })
  }));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(function(req, res, next){
    req.user = null;
    if(req.session.passport && req.session.passport.user){
      User.findById(req.session.passport.user, function(err, user){
        if(err) return next(err);
        user.password = null;
        req.user = user;
        next();
      })
    } else {
      next();
    }
  })

markdown 和內(nèi)容驗(yàn)證

這個(gè)功能之前去找了 github 中 "markdown" 排第一的 node 插件 marked 插件實(shí)現(xiàn)。關(guān)于插件這里不多說了。這里重點(diǎn)說一下的內(nèi)容驗(yàn)證,因?yàn)閮?nèi)容驗(yàn)證是安全性保障的重要一個(gè)環(huán)節(jié)。這里即要保障惡意腳步不會(huì)被提交,或運(yùn)行,而且還要保障 markdown 可以很好的轉(zhuǎn)換數(shù)據(jù)。對(duì)于輸入的字符串處理,博主自己實(shí)現(xiàn)了幾個(gè)工具函數(shù):

var clearUtil = function(app){};

// 清除 XML 標(biāo)簽
clearUtil.clearXMLTags = function(str, deeply){
  var deeply = deeply || false;
  var temp = str.replace(/<[^>]+>/g, "");
  if(deeply){
    temp = temp.replace(/[
][
]+/g, "");
  }
  return temp;
};

// 清除 script 標(biāo)簽及內(nèi)容
clearUtil.clearScripts = function(str){
  return str.replace(//ig,"");
};

// 清除換號(hào)符 CR/LF
clearUtil.clearReturns = function(str){
  return str.replace(/[
]/g, "");
};

// 轉(zhuǎn)義 xml 尖括號(hào)
clearUtil.TransferTags = function(str){
  var temp = str.concat();
  temp = temp.replace(//g, ">");
  return temp;
};

module.exports = clearUtil;

性能優(yōu)化

這個(gè)部分,主要工作是代碼壓縮,和緩存利用。
壓縮方法都是十分主流的方法,利用
imagemin, clean-css, uglify, 壓縮了圖片,css 和 js, 同時(shí)網(wǎng)頁(yè)以 gzip 格式傳輸,減小體積。
同時(shí),對(duì) css 和 js 附加緩存,配合 E-Tag 和 版本號(hào)實(shí)現(xiàn)服務(wù)器更新,這一部分其實(shí) Express 已經(jīng)幫我們實(shí)現(xiàn)好了。所以這個(gè)部分,主要十幾個(gè) gulp 配置

gulp.task("sass", function () {
  gulp.src("./source/css/**/*.scss")
    .pipe(autoprefix())
    .pipe(sass())
    .pipe(clearCss())
    .pipe(gulp.dest("./dist/css"))
    .pipe(browserSync.reload({stream:true}));
});
gulp.task("imagemin", function(){
  gulp.src("./source/img/*.{png,jpg,gif,ico}")
    .pipe(imagemin())
    .pipe(gulp.dest("./dist/img"));
});
gulp.task("minifyjs", function() {
  return gulp.src("./source/js/**/*.js")
    .pipe(rename({suffix: ".min"}))
    .pipe(uglify())
    .pipe(gulp.dest("./dist/js"));
});

偷懶配置

博主用了一個(gè) CentOS 的服務(wù)器,其實(shí)通過 scp 和 ssh 就可以實(shí)現(xiàn)上傳和配置了,但依據(jù)“進(jìn)步源于懶惰”的碼農(nóng)提高準(zhǔn)則,博主還是做了一個(gè)自己上傳部署的功能:

/* part of gulpfile.js */
var shell = require("gulp-shell");
var ssh = require("gulp-ssh");
var deployConfig = require("./deploy-config");
var gulpSequence = require("gulp-sequence");
var zip = require("gulp-zip");
var through = require("through2");
var async = require("async");
var scpClient = require("scp2");
var gulpUtil = require("gulp-util");
var deploySSH = require("./deploy-ssh");

//上傳功能實(shí)現(xiàn)主任務(wù)
gulp.task("up", function (){
  shell.task(["rm -rf publish"]);
  gulpSequence("copyFile", "zipFile", "deploy",  function() {
    gulpUtil.log(PLUGIN_NAME, "***** Deploy Finished!?。?!");
    process.exit(0);
  });
});

gulp.task("copyFile", function() {
  return gulp.src([
    "node_modules/**",
    "*.json",
    "*.js",
    "app/**",
    "config/**",
    "dist/**",
    "!config.js"
  ], { base: "./"})
  .pipe(gulp.dest("./publish"));
});

gulp.task("zipFile", function() {
  return gulp.src(["publish/**"], { base: "./" })
    .pipe(zip("publish.zip"))
    .pipe(gulp.dest("./publish"));
});

gulp.task("deploy", function() {
  var config = deployConfig.production;
  config.deployPath = "/home/faremax/website/publish/";
  return gulp.src("publish/publish.zip", { base: "./" })
    .pipe(deploySSH({
    servers: config.servers,
    dest: config.deployPath + "publish.zip",
    logPath: "deploy",
    shell:[
      "cd " + config.deployPath,
      "shopt -s extglob",
      "rm -rf !(logs|node_modules|config.js|publish.zip)",
      "unzip -o publish.zip",
      "cp -rf publish/** .",
      "rm -rf publish",
      "rm publish.zip",
      "npm install --production",
      "pm2 startOrRestart pm2-start.json"
    ],
  }));
});
/* deploy-ssh.js */
var gulp = require("gulp");
var gutil = require("gulp-util");
var through = require("through2");
var ScpClient = require("scp2").Client;
var ssh = require("gulp-ssh");
var async = require("async");
var ProgressBar = require("progress");

const PLUGIN_NAME = "deploy-ssh"

module.exports = function (options) {
  var servers = options.servers;
  var dest = options.dest;
  var shell = options.shell;
  var logPath = options.logPath;

  return through.obj(function (file, enc, callback) {
    if (file.isNull()) {
      callback(null, file);
      return;
    }

    if (file.isStream()) {
      return callback(new gutil.PluginError(PLUGIN_NAME, "No stream support"));
    }

    var i = 0;
    async.eachSeries(servers, function(server, done) {
      var hostName = server.sshConfig.host;
      gutil.log(PLUGIN_NAME, "start deploy:" + hostName)
      var client = new ScpClient(server.sshConfig);

      var bar = null;
      client.on("transfer",  function(buffer, uploaded, total){
        if(bar == null){
          bar = new ProgressBar(hostName + " uploading [:bar] :percent :elapsed s", {
            complete: "=",
            incomplete: " ",
            width: 50,
            total: total
          });
        }
        bar.tick(1);
      });

      client.write({
        destination: dest,
        content: file.contents
      }, function () {
        ssh(server).shell(shell, {filePath: logPath + "-" + hostName + ".log", autoExit: true}).on("error", function (err) {
          done(err);

          gutil.PluginError(PLUGIN_NAME,  err)
        }).on("finish", function () {
          gutil.log(PLUGIN_NAME, "finish deploy:" + hostName);

          done();

          if (++i === servers.length) {
            callback(null, file);
          }
        }).pipe(gulp.dest("logs"));
      });
    });

  });

};
/* deploy-config.js */
var config = {
  production:{
    servers:[
    {
      sshConfig: {
        host: "114,214,132,211",
        port: 80,
        username: "******",
        password: "******",
        readyTimeout: 600000
      }
    }]
  }
};

module.exports = config;
網(wǎng)站實(shí)現(xiàn)效果

從功能上來看,其實(shí)僅僅實(shí)現(xiàn)了博客展示、博客的管理和分類管理3個(gè)基本部分,前臺(tái)是給用戶看的,花的時(shí)間比較多,還有就是安全,這個(gè)不能大意。

前臺(tái)效果,這個(gè)大家都能看到,不說了:

當(dāng)然,前臺(tái)還有移動(dòng)端:

后臺(tái)效果,東西不多,界面很簡(jiǎn)潔,很多東西還需要逐步添加:

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97657.html

相關(guān)文章

  • 個(gè)人博客主頁(yè)搭建隨筆

    摘要:博主目前的這個(gè)項(xiàng)目還不算很大,模塊依賴簡(jiǎn)單,但期望完成諸如版本號(hào)替換,壓縮代碼,合并文件,發(fā)布到服務(wù)器等和模塊化關(guān)系不大的工作,所以使用了。同時(shí),對(duì)和附加緩存,配合和版本號(hào)實(shí)現(xiàn)服務(wù)器更新,這一部分其實(shí)已經(jīng)幫我們實(shí)現(xiàn)好了。 經(jīng)常在各種論壇、博客還有 github 上活躍的朋友不難發(fā)現(xiàn),許多大牛都有自己的網(wǎng)站,也多以博客為主。博主作為一個(gè)立志前端的大白,難道不應(yīng)該和大牛學(xué)習(xí)么?說干就干,前...

    whjin 評(píng)論0 收藏0
  • 手把手教你使用Hexo + Github Pages搭建個(gè)人獨(dú)立博客

    摘要:設(shè)置什么是本用于介紹托管在的項(xiàng)目,不過,由于他的空間免費(fèi)穩(wěn)定,用來做搭建一個(gè)博客再好不過了。你可以通過來訪問你的個(gè)人主頁(yè)。執(zhí)行過程中可能需要讓你輸入賬戶的用戶名及密碼,按照提示操作即可。推薦使用騰訊公益。 系統(tǒng)環(huán)境配置 要使用Hexo,需要在你的系統(tǒng)中支持Nodejs以及Git,如果還沒有,那就開始安裝吧! 安裝Node.js 下載Node.js參考地址:安裝Node.js 安裝Git...

    劉福 評(píng)論0 收藏0
  • 一個(gè)JAVA WEB偽全棧的VUE入坑隨筆:從登錄開始(VUEX)

    摘要:此文章用于記錄本人學(xué)習(xí)歷程,有共同愛好者可加好友一起分享。從上周天,由于本周有公司籃球比賽,所以耽誤兩天晚上,耗時(shí)三個(gè)晚上勉強(qiáng)做了一個(gè)登錄功能。這里的用戶信息和登錄狀態(tài)都是直接取的中的用戶信息進(jìn)行屬性值初始化。 此文章用于記錄本人VUE學(xué)習(xí)歷程,有共同愛好者可加好友一起分享。從上周天,由于本周有公司籃球比賽,所以耽誤兩天晚上,耗時(shí)三個(gè)晚上勉強(qiáng)做了一個(gè)登錄功能。中間的曲折只有自己知道,有...

    Zack 評(píng)論0 收藏0
  • 【HEXO】從零搭建HEXO博客 修改默認(rèn)主題/參數(shù)/favicon 替換個(gè)人主頁(yè)

    摘要:下面我以主題舉例,覆蓋默認(rèn)主題。其他元素使用相同的方法都可以修改。像這種超鏈接跳轉(zhuǎn)的修改,在文件中找到直接把屬性的值改變即可。 準(zhǔn)備:搭建環(huán)境 大致分為以下兩步: 安裝Node.js 安裝git 配置Node.js環(huán)境 下載Node.js安裝 Windows Installer 32-bithttps://nodejs.org/dist/v4.2.3/node-v4.2.3-x...

    My_Oh_My 評(píng)論0 收藏0
  • 【HEXO】從零搭建HEXO博客 修改默認(rèn)主題/參數(shù)/favicon 替換個(gè)人主頁(yè)

    摘要:下面我以主題舉例,覆蓋默認(rèn)主題。其他元素使用相同的方法都可以修改。像這種超鏈接跳轉(zhuǎn)的修改,在文件中找到直接把屬性的值改變即可。 準(zhǔn)備:搭建環(huán)境 大致分為以下兩步: 安裝Node.js 安裝git 配置Node.js環(huán)境 下載Node.js安裝 Windows Installer 32-bithttps://nodejs.org/dist/v4.2.3/node-v4.2.3-x...

    Near_Li 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<