• 多人博客网站第一版上线啦,欢迎围观,吐槽


    网站地址

    代码开源地址

    时间大概是在两年前吧,那时候刚接触到 nodejs,立志成为一名优秀全栈攻城狮的我,心心念着得有一个属于自己的网站。于是说干就干,一边学着一边捣鼓的各种花样。

    曾梦想仗剑走天涯,然而后面因为工作忙就没去成,我的这个网站也因为各种原因迟迟没能上线,这其中也做过了好几个版本,一开始是前后端分离的,前端使用 angularjs(后面又改成了 vue),后端是 nodejs + mongodb,等这一版的也差不多做好的时候,感觉不是自己想要的样子,所以也就没上线。到后面觉得 golang 好玩,又去用它写了一些后端的接口。

    到了今年三月份的时候,终于发现网站这个目标确实是拖了很长时间了。抽时间好好想了下自己想要做什么,决定抛弃之前的那套代码,不用自己比较熟悉的 前后端分离,vue 等技术,而使用 ejs 模板渲染,nodejs 的 Sequelize orm 库,使用 session 而不是 jwt 来持久化用户登录等。

    代码基本上是晚上抽时间写的,后面因为加班,也停了一段时间。中途如果遇到一些问题,有时候进度也会耽搁个几天。再加上一些设计以及前端展示上的修修补补,导致整个项目也是花了比较长的时间。好在是一个萝卜一个坑的慢慢踩了过来,现在觉得网站终于可以上线了,后面要做的工作就是完善网站的一些没有功能(包括后端的管理界面等),修改一些的实现方式(准确的说就是优化代码),以及更重要的是丰富网站内容,也就是写博客记录一些成长路上的风景吧。

    到此为止,废话也不多说了,代码也开源到了GitHub上,有兴趣的朋友可以去围观一下,欢迎 start,也欢迎在 issue 里提出,指正各种问题。

    说一下项目的运行方式吧,首先要 nodejs 环境,需要全局安装 gulp、nodemon 等包,然后数据存储使用的 mysql + redis。等环境准备好了之后,就需要添加一些配置文件,比如在 config/env/ 下创建 development.js 文件,里面需要提供发邮箱的邮件地址,以及 github 第三方登录的 clientID 等。

    module.exports = {
    	email: {
    		account: '',
    		pwd: ''
    	},
        github: {
            clientID: '',
            clientSecret: '',
            callbackUrl: ``
        }
    };

    接下来就是安装开发运行所需要的各种依赖包吧,跑一下 yarn install 就行了,这个过程可能需要花个几分钟时间。
    等到所有的包都安装完毕后,直接跑 npm start 命令,看到 终端上显示 所有的 gulp 任务 finished,Server is running at port 3000 的时候,就可以打开浏览器访问 localhost:3000 了。
    接下来贴上一些项目里面的代码吧,如果上不了首页就悲剧了。

     1 require('dotenv').config()
     2 
     3 const express = require('express')
     4 const passport = require('passport')
     5 const models = require('./config/db/model')
     6 const port = process.env.PORT
     7 
     8 const app = express()
     9 
    10 require('./config/passport')(passport)
    11 require('./config/express')(app, passport)
    12 require('./config/routes')(app, passport)
    13 
    14 models
    15     .sequelize
    16     .sync()
    17     .then(() => {
    18         app.listen(port, () => {
    19             console.log(`Server is running at port ${port}`)
    20         })
    21     })
    22 
    23 module.exports = app


    Gulp 的打包配置

      1 // vinyl 是一个简单的描述文件的元数据对象
      2 // https://github.com/gulpjs/vinyl
      3 const path = require('path')
      4 const gulp = require('gulp')
      5 const del = require('del')
      6 const glob = require('glob')
      7 const babelify = require('babelify')
      8 const runSequence = require('run-sequence')
      9 const plumber = require('gulp-plumber')
     10 const notify = require('gulp-notify')
     11 const gulpif = require('gulp-if')
     12 const sass = require('gulp-sass')
     13 const debug = require('gulp-debug')
     14 const cached = require('gulp-cached')
     15 const remember = require('gulp-remember')
     16 const autoprefixer = require('gulp-autoprefixer')
     17 const sourcemaps = require('gulp-sourcemaps');
     18 const size = require('gulp-size');
     19 const cssnano = require('gulp-cssnano')
     20 const uglify = require('gulp-uglify')
     21 const rename = require('gulp-rename')
     22 const htmlmin = require('gulp-htmlmin')
     23 const imagemin = require('gulp-imagemin')
     24 const browserify = require('browserify')
     25 const source = require('vinyl-source-stream');
     26 const buffer = require('vinyl-buffer');
     27 const rev = require('gulp-rev');
     28 const watchify = require('watchify')
     29 const lazypipe = require('lazypipe')
     30 const revCollector = require('gulp-rev-collector');
     31 const es = require('event-stream')
     32 const argv = require('yargs').argv
     33 
     34 // 将打包后的静态资源 放到nginx服务器上
     35 const bundleAssetsDir = argv.build_mode === 'deploy' && argv.assets_path ? argv.assets_path : './public/static/'
     36 const jsAssetsDir = path.join(bundleAssetsDir, 'js')
     37 const cssAssetsDir = path.join(bundleAssetsDir, 'css')
     38 const imgAssetsDir = path.join(bundleAssetsDir, 'image')
     39 const revAssetsDir = path.join(bundleAssetsDir, 'rev')
     40 const htmlAssetsDir = path.join('./app/view')
     41 
     42 const AUTOPREFIXER_BROWSERS = [
     43     'ie >= 10',
     44     'ff >= 30',
     45     'chrome >= 34',
     46     'safari >= 7',
     47     'opera >= 23'
     48 ];
     49 
     50 const jsChannel = lazypipe()
     51     .pipe(uglify)
     52     .pipe(gulp.dest, jsAssetsDir)
     53 
     54 let watch = false
     55 
     56 function getEntryFiles (path, option) {
     57     return glob.sync(path, option)
     58 }
     59 
     60 /**
     61  * 打包js任务
     62  * @param {Object} bundle 各入口文件的browserify对象
     63  * @param {string} filename 入口文件名
     64  * @return {stream} stream 对象
     65  */
     66 function jsTask ({ bundle, filename }) {
     67     return bundle
     68     .bundle()
     69     .pipe(plumber({
     70         errorHandler: notify.onError('Error: <%= error.message %>')
     71     }))
     72     .pipe(source(filename))
     73     // 代替 gulp-streamify,来转换 vinyl 流
     74     .pipe(buffer())
     75     .pipe(rename({ dirname: '' }))
     76     .pipe(sourcemaps.init())
     77     .pipe(debug({ title: 'script' }))
     78     .pipe(size({ title: 'script' }))
     79     .pipe(sourcemaps.write(''))
     80     .pipe(gulp.dest(jsAssetsDir))
     81 }
     82 
     83 /**
     84  * 如果一个文件被删除了,则将其忘记
     85  * @param {*} event
     86  */
     87 function watchDel (event) {
     88     if (event.type === 'deleted') {
     89         // gulp-cached 的删除 api
     90         delete cached.caches.scripts[event.path]
     91         // gulp-remember 的删除 api
     92         remember.forget('scripts', event.path)
     93     }
     94 }
     95 
     96 gulp.task('style', () => {
     97     return gulp.src('./src/scss/*.scss')
     98         .pipe(plumber({
     99             errorHandler: notify.onError('Error: <%= error.message %>')
    100         }))
    101         // .pipe(cached('style-task'))
    102         .pipe(sourcemaps.init())
    103         .pipe(sass())
    104         .pipe(cssnano({
    105             // 不修改 z-index
    106             safe: true
    107         }))
    108         .pipe(autoprefixer(AUTOPREFIXER_BROWSERS))
    109         .pipe(debug({ title: 'style' }))
    110         // .pipe(remember('style-task'))
    111         .pipe(size({ title: 'style' }))
    112         .pipe(sourcemaps.write(''))
    113         .pipe(gulp.dest(cssAssetsDir))
    114 })
    115 
    116 gulp.task('script', () => {
    117     let entryJs = getEntryFiles('./src/js/*.js')
    118     let bundleTasks = entryJs.map(filename => {
    119         const bundle = browserify({
    120             entries: [filename],
    121             cache: {},
    122             packageCache: {},
    123             plugin: [watch ? watchify : null],
    124             transform: babelify
    125         })
    126         if (watch) {
    127             bundle.on('update', function () {
    128                 jsTask.call(null, { bundle, filename })
    129             })
    130         }
    131         return { bundle, filename }
    132     })
    133     return es.merge(bundleTasks.map(jsTask));
    134 })
    135 
    136 gulp.task('image', () => {
    137     return gulp.src(['./src/image/*', './src/image/**/*'])
    138         .pipe(cached('image-task'))
    139         .pipe(imagemin([
    140             imagemin.gifsicle({ interlaced: true }),
    141             imagemin.jpegtran({ progressive: true }),
    142             imagemin.optipng({ optimizationLevel: 5 }),
    143             imagemin.svgo({
    144                 plugins: [
    145                     { removeViewBox: true },
    146                     { cleanupIDs: false }
    147                 ]
    148             })
    149         ]))
    150         .pipe(debug({ title: 'image' }))
    151         .pipe(remember('image-task'))
    152         .pipe(size({ title: 'image' }))
    153         .pipe(gulp.dest(imgAssetsDir))
    154 })
    155 
    156 gulp.task('html', () => {
    157     return gulp.src('./src/page/**/*.html')
    158         .pipe(cached('html-task'))
    159         .pipe(debug({ title: 'html' }))
    160         .pipe(remember('html-task'))
    161         .pipe(gulp.dest(htmlAssetsDir))
    162 
    163 })
    164 
    165 gulp.task('rev', () => {
    166     return gulp.src([path.join(jsAssetsDir, '*.js'), path.join(cssAssetsDir, '*.css')])
    167         .pipe(rev())
    168         .pipe(gulpif('*.js', jsChannel()))
    169         .pipe(gulpif('*.css', gulp.dest(cssAssetsDir)))
    170         .pipe(rev.manifest({
    171             merge: true
    172         }))
    173         .pipe(gulp.dest(revAssetsDir))
    174 })
    175 
    176 gulp.task('rev-collector', () => {
    177     return gulp.src([path.join(revAssetsDir, '*.json'), path.join(htmlAssetsDir, '*.html')])
    178         .pipe(revCollector({
    179             replaceReved: true
    180         }))
    181         .pipe(htmlmin({
    182             removeComments: true,
    183             collapseWhitespace: true,
    184             collapseBooleanAttributes: true,
    185             removeAttributeQuotes: true,
    186             removeRedundantAttributes: true,
    187             removeEmptyAttributes: true,
    188             removeScriptTypeAttributes: true,
    189             removeStyleLinkTypeAttributes: true,
    190             removeOptionalTags: true
    191         }))
    192         .pipe(size({ title: 'html' }))
    193         .pipe(gulp.dest(htmlAssetsDir))
    194 })
    195 
    196 gulp.task('clean', () => del([bundleAssetsDir, htmlAssetsDir], { force: true }))
    197 
    198 gulp.task('style:watch', () => {
    199     const watcher = gulp.watch(['./src/scss/**/*.scss'], ['style'])
    200     watcher.on('change', watchDel)
    201 })
    202 
    203 gulp.task('image:watch', () => {
    204     const watcher = gulp.watch(['./src/image/**/*'], ['image'])
    205     watcher.on('change', watchDel)
    206 }
    207 )
    208 gulp.task('html:watch', () => {
    209     const watcher = gulp.watch(['./src/page/**/*.html'], ['html'])
    210     watcher.on('change', watchDel)
    211 })
    212 
    213 gulp.task('watch', () => {
    214     watch = true
    215     runSequence(
    216         'clean',
    217         ['script', 'style', 'html', 'image'],
    218         ['style:watch', 'html:watch', 'image:watch']
    219     )
    220 })
    221 
    222 gulp.task('build', cb => {
    223     watch = false
    224     return runSequence(
    225         'clean',
    226         ['script', 'style', 'html', 'image'],
    227         'rev',
    228         'rev-collector',
    229         cb
    230     )
    231 })
    232 
    233 gulp.task('default', ['build'])

    最后再一次贴上网站以及开源地址,欢迎各路大佬围观,吐槽,指正。

    网站地址

    代码开源地址

  • 相关阅读:
    unity assert server 与 cache server
    Excel文件读写
    String与StringBuilder之间区别(转)
    c# 文件遍历
    C#整数三种强制类型转换int、Convert.ToInt32()、int.Parse()的区别
    2014年读过的书总结
    求职在年末
    被辞退于年末
    Unity Svn(转)
    公司的人员流动
  • 原文地址:https://www.cnblogs.com/ww-ervin-72/p/11319795.html
Copyright © 2020-2023  润新知