从0开始一个nodejs博客项目
ECMAScript2015(es6)
1、项目构建
1.1、基础架构
- 业务逻辑:
- 页面
- 交互
- 自动构建:babel、webpack
- 编译
- 辅助:
- 自动刷新
- 文件合并
- 资源压缩
- 服务接口
- 数据
- 接口
1.2、项目创建
创建es6文件夹:
-
app放置前端代码
- css
- js
- class:类文件夹
- index.js:入口文件
- views:express框架使用ejs引擎所以后缀不是html而是ejs
- index.ejs:入口文件
- error.ejs:错误文件
-
server放置服务器代码
-
启动脚手架:
// express:脚手架启动命令 // -e 使用ejs引擎 // . 在当前目录执行 express -e . -
初始化:npm i
-
-
tasks放置工具
- utils:常用脚本
-
.babelrc:babel配置文件
-
gulpfile.babel.js:gulp配置文件,因为项目使用es6,需要使用babel对es6代码进行编译,所以创建gulpfile.babel.js文件,而不是创建官网推荐的gulpfile.js文件
1.3、命令行处理、创建js编译任务
-
新建tasks/utils/args.js:对命令行参数进行解析的构建脚本
import yargs from 'yargs' const args = yargs // 区分命令行有没有这个参数,用于区分是线上环境还是开发环境 .option('production', { // 这个选项是一个布尔值 boolean: true, // 默认值为false,也就是如果没有production这个参数,默认为开发环境 default: false, // 描述,机器不识别 describe: 'min all scripts' }) // 监听开发环境中修改文件后,需不需要自动编译 .option('watch', { boolean: true, default: false, describe: 'watch all files' }) // 需不需要命令行详细输出目录日志 .option('verbose', { boolean: true, default: false, describe: 'watch all files' }) .option('sourcemaps', { describe: 'force the creation of sourcemaps' }) // 设置端口 .option('port', { string: true, default: 8080, describe: 'server port' }) // 对输入的命令行,以字符串进行解析 .argv export default args -
新建tasks/scripts.js:对js进行处理的构建脚本
import gulp from 'gulp' // gulp中对语句进行if判断 import gulpif from 'gulp-if' // gulp中对文件进行拼接 import concat from 'gulp-concat' // 打包 import webpack from 'webpack' // gulp处理的都是一些文件流,他是基于stream,所以对webpack的处理要结合webpack-stream import gulpWebpack from 'webpack-stream' // 对文件重命名做标志 import named from 'vinyl-named' // 文件修改后,对浏览器自动刷新 import livereload from 'gulp-livereload' // 处理文件信息流 import plumber from 'gulp-plumber' // 对文件重命名 import rename from 'gulp-rename' // 处理js压缩和css压缩 import uglify from 'gulp-uglify' // 在命令行进行输出 import { log, colors } from 'gulp-util' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('scripts', () => { // 打开app/js/index.js return gulp.src(['app/js/index.js']) // 处理常规的错误逻辑,每一个pipe的时候,出现错误都要抛出异常 .pipe(plumber({ // 集中处理错误,改正默认处理错误的机制 errorHandle(){ } })) // 对文件重新命名 .pipe(named()) // 对js进行编译 .pipe(gulpWebpack({ module:{ loaders:[{ test:/\.js$/, loader:'babel' }] } }), null, (err,states) => { // 处理错误 log(`Finished '${colors.cyan('scripts')}'`, states.toString({ chunks:false })); }) // 编译好的文件放入server/public/js .pipe(gulp.dest('server/public/js')) // 对编译好的文件文件进行重命名 .pipe(rename({ basename:'cp', extname:'.min.js' })) // 对编译好的文件文件进行压缩 .pipe(uglify({compress:{properties:false}, output:{'quote_keys':true}})) // 压缩后的文件放入server/public/js .pipe(gulp.dest('server/public/js')) // 监听文件变化后自动刷新 .pipe(gulpif(args.watch, livereload())) }) -
初始化:
-
初始化pages.json:npm init
-
安装需要使用包,修改pages.json中代码,然后直接安装:npm i
{ "name": "es6", "version": "1.0.0", "description": "", "main": "gulpfile.babel.js", "devDependencies": { "babel-core": "^6.24.0", "babel-loader": "^6.4.1", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-polyfill": "^6.23.0", "babel-preset-env": "^1.2.2", "babel-preset-es2015": "^6.24.0", "babel-register": "^6.26.0", "connect-livereload": "^0.6.0", "del": "^2.2.2", "gulp": "^3.9.1", "gulp-concat": "^2.6.1", "gulp-if": "^2.0.2", "gulp-live-server": "0.0.30", "gulp-livereload": "^3.8.1", "gulp-plumber": "^1.1.0", "gulp-rename": "^1.2.2", "gulp-sequence": "^0.4.6", "gulp-uglify": "^2.1.0", "gulp-util": "^3.0.8", "require-dir": "^0.3.2", "vinyl-named": "^1.1.0", "webpack": "^2.2.1", "webpack-stream": "^3.2.0", "yargs": "^7.0.2" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
-
1.4、创建模板、服务任务脚本
-
新建tasks/pages.js:
import gulp from 'gulp' // gulp中对语句进行if判断 import gulpif from 'gulp-if' // 文件修改后,对浏览器自动刷新 import livereload from 'gulp-livereload' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('pages', () => { // 打开app下所有ejs文件 return gulp.src(['app/**/*.ejs']) // 将模板文件拷贝到server文件中 .pipe(gulp.dest('server')) // 监听文件变化后自动刷新 .pipe(gulpif(args.watch, livereload())) }) -
新建tasks/css.js:
import gulp from 'gulp' // gulp中对语句进行if判断 import gulpif from 'gulp-if' // 文件修改后,对浏览器自动刷新 import livereload from 'gulp-livereload' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('css', () => { // 打开app下所有css文件 return gulp.src(['app/**/*.css']) // 将模板文件拷贝到server/public文件中 .pipe(gulp.dest('server/public')) // 监听文件变化后自动刷新 .pipe(gulpif(args.watch, livereload())) }) -
新建tasks/server.js:
import gulp from 'gulp' // gulp中对语句进行if判断 import gulpif from 'gulp-if' // 启动服务器 import liveserver from 'gulp-live-server' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('server', (cb) => { // 如果不是处于监听状态下,直接返回回调函数 if(!args.watch) return cb() // 如果是处于监听状态下,创建一个服务器 // --harmony:在当前目录行下,执行后面的脚本 // server/bin/www:脚本 var server = liveserver.new(['--harmony', 'server/bin/www']) // 启动服务器 server.start() // 监听server/public目录下的所有js文件和server/views目录下的所有ejs文件的改变 gulp.watch(['server/public/**/*.js','server/views/**/*.ejs'], function(file){ server.notify.apply(server, [file]) }) // 监听需要重启服务才能生效的文件 gulp.watch(['server/routes/**/*.js', 'server/app.js'], function(){ // 重启服务 server.start.bind(server()) }) })
1.5、文件自动监听
-
新建tasks/browser.js:
import gulp from 'gulp' // gulp中对语句进行if判断 import gulpif from 'gulp-if' // gulp常用的工具函数集合 import gutil from 'gulp-util' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('browser', (cb) => { // 如果不是处于监听状态下,直接返回回调函数 if(!args.watch) return cb() // app下所有js文件发生改变时,执行scripts.js脚本 gulp.watch('app/**/*.js', ['scripts']) // app下所有ejs文件发生改变时,执行pages.js脚本 gulp.watch('app/**/*.ejs', ['pages']) // app下所有css文件发生改变时,执行css.js脚本 gulp.watch('app/**/*.css', ['css']) }) -
新建tasks/clean.js:清空指定文件
import gulp from 'gulp' // 删除 import del from 'del' // 对命令行参数进行解析 import args from './utils/args' // 创建一个脚本编译的任务 gulp.task('clean', (cb) => { return del(['server/public', 'server/views']) }) -
新建tasks/build.js:关联所有任务
import gulp from 'gulp' import gulpSequence from 'gulp-sequence' // 指定顺序执行 gulp.task('build', gulpSequence('clean', 'css', 'pages', 'scripts', ['browser', 'server'])) -
新建tasks/default.js:命令行执行gulp命令时,默认执行的文件
import gulp from 'gulp' // 指定顺序执行 gulp.task('default', ['build']) -
修改gulpfile.babel.js:
import requireDir from 'require-dir' // 引入tasks目录下的脚本 requireDir('./tasks') -
修改.babelrc:
{ "presets": ["es2015"] } -
如果执行命令 gulp --watch 报错 primordials is not defined:
-
删除node_modules
-
在package.json的同级目录中创建npm-shrinkwrap.json
-
在创建的npm-shrinkwrap.json中复制以下内容:
{ "dependencies": { "graceful-fs": { "version": "4.2.2" } } }
-
-
报错:Failed to lookup view “error” in views directory
-
修改server/app.js:
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use(require('connect-livereload')()) app.use('/', indexRouter); app.use('/users', usersRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app; -
新增app/views/error.ejs
-
从0开始一个nodejs博客项目
http://localhost:8090//archives/nodejsblog