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

网站地址

代码开源地址

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

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

网站地址

代码开源地址

posted on 2019-08-08 10:46  蜀北乔少恭  阅读(423)  评论(0编辑  收藏  举报

导航