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

2022-10-17,,,

时间大概是在两年前吧,那时候刚接触到 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'])

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

《多人博客网站第一版上线啦,欢迎围观,吐槽.doc》

下载本文的Word格式文档,以方便收藏与打印。