从0开始一个nodejs博客项目

ECMAScript2015(es6)

1、项目构建

1.1、基础架构

  1. 业务逻辑:
    • 页面
    • 交互
  2. 自动构建:babel、webpack
    • 编译
    • 辅助:
      • 自动刷新
      • 文件合并
      • 资源压缩
  3. 服务接口
    • 数据
    • 接口

1.2、项目创建

创建es6文件夹:

  1. app放置前端代码

    • css
    • js
      • class:类文件夹
      • index.js:入口文件
    • views:express框架使用ejs引擎所以后缀不是html而是ejs
      • index.ejs:入口文件
      • error.ejs:错误文件
  2. server放置服务器代码

    1. 启动脚手架:

      // express:脚手架启动命令
      // -e 使用ejs引擎
      // . 在当前目录执行
      express -e . 
      
    2. 初始化:npm i

  3. tasks放置工具

    • utils:常用脚本
  4. .babelrc:babel配置文件

  5. gulpfile.babel.js:gulp配置文件,因为项目使用es6,需要使用babel对es6代码进行编译,所以创建gulpfile.babel.js文件,而不是创建官网推荐的gulpfile.js文件

1.3、命令行处理、创建js编译任务

  1. 新建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
    
  2. 新建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()))
    })
    
  3. 初始化:

    • 初始化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、创建模板、服务任务脚本

  1. 新建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()))
    })
    
  2. 新建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()))
    })
    
  3. 新建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、文件自动监听

  1. 新建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'])
    })
    
  2. 新建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'])
    })
    
  3. 新建tasks/build.js:关联所有任务

    import gulp from 'gulp'
    
    import gulpSequence from 'gulp-sequence'
    
    // 指定顺序执行
    gulp.task('build', gulpSequence('clean', 'css', 'pages', 'scripts', ['browser', 'server']))
    
  4. 新建tasks/default.js:命令行执行gulp命令时,默认执行的文件

    import gulp from 'gulp'
    
    // 指定顺序执行
    gulp.task('default', ['build'])
    
  5. 修改gulpfile.babel.js:

    import requireDir from 'require-dir'
    
    // 引入tasks目录下的脚本
    requireDir('./tasks')
    
  6. 修改.babelrc:

    {
        "presets": ["es2015"]
    }
    
  7. 如果执行命令 gulp --watch 报错 primordials is not defined:

    • 删除node_modules

    • 在package.json的同级目录中创建npm-shrinkwrap.json

    • 在创建的npm-shrinkwrap.json中复制以下内容:

      {
         "dependencies": {
             "graceful-fs": {
                 "version": "4.2.2"
             }
         }
      }
      
  8. 报错: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
作者
龟龟
发布于
2021年08月24日
更新于
2024年08月28日
许可协议