網站地址javascript
代碼開源地址css
時間大概是在兩年前吧,那時候剛接觸到 nodejs,立志成爲一名優秀全棧攻城獅的我,心心念着得有一個屬於本身的網站。因而說幹就幹,一邊學着一邊搗鼓的各類花樣。html
曾夢想仗劍走天涯,然然後面由於工做忙就沒去成,個人這個網站也由於各類緣由遲遲沒能上線,這其中也作過了好幾個版本,一開始是先後端分離的,前端使用 angularjs(後面又改爲了 vue),後端是 nodejs + mongodb,等這一版的也差很少作好的時候,感受不是本身想要的樣子,因此也就沒上線。到後面以爲 golang 好玩,又去用它寫了一些後端的接口。前端
到了今年三月份的時候,終於發現網站這個目標確實是拖了很長時間了。抽時間好好想了下本身想要作什麼,決定拋棄以前的那套代碼,不用本身比較熟悉的 先後端分離,vue 等技術,而使用 ejs 模板渲染,nodejs 的 Sequelize orm 庫,使用 session 而不是 jwt 來持久化用戶登陸等。vue
代碼基本上是晚上抽時間寫的,後面由於加班,也停了一段時間。中途若是遇到一些問題,有時候進度也會耽擱個幾天。再加上一些設計以及前端展現上的修修補補,致使整個項目也是花了比較長的時間。好在是一個蘿蔔一個坑的慢慢踩了過來,如今以爲網站終於能夠上線了,後面要作的工做就是完善網站的一些沒有功能(包括後端的管理界面等),修改一些的實現方式(準確的說就是優化代碼),以及更重要的是豐富網站內容,也就是寫博客記錄一些成長路上的風景吧。java
到此爲止,廢話也很少說了,代碼也開源到了GitHub上,有興趣的朋友能夠去圍觀一下,歡迎 start,也歡迎在 issue 裏提出,指正各類問題。node
說一下項目的運行方式吧,首先要 nodejs 環境,須要全局安裝 gulp、nodemon 等包,而後數據存儲使用的 mysql + redis。等環境準備好了以後,就須要添加一些配置文件,好比在 config/env/ 下建立 development.js 文件,裏面須要提供發郵箱的郵件地址,以及 github 第三方登陸的 clientID 等。mysql
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 的打包配置nginx
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'])
最後再一次貼上網站以及開源地址,歡迎各路大佬圍觀,吐槽,指正。git