全栈es6、7的js开发-基于Sails

Author image Cloud on 前端 , Web , Sails , Express
Karat克拉这个网站,就是基于sails开发的,前后端都启用了es6+es7特性的开发。我在github上传了部署代码和文档:https://github.com/xunuoi/sails-babel 修改变动比较多,github上可能不是最新的代码和文档。主要是用了一个支持babel的hook和babel的gulp组件,来支援es6~新建一个空sails项目,不包含前端:sails new withu.cc --no-frontend --template=swig修改.sailssrc1、添加如下,否则启动sails lift会有找不到grunt的

Karat克拉这个网站,就是基于sails开发的,前后端都启用了es6+es7特性的开发。

我在github上传了部署代码和文档:https://github.com/xunuoi/sails-babel 

修改变动比较多,github上可能不是最新的代码和文档。


主要是用了一个支持babel的hook和babel的gulp组件,来支援es6~


新建一个空sails项目,不包含前端:

sails new withu.cc --no-frontend --template=swig

修改.sailssrc

1、添加如下,否则启动sails lift会有找不到grunt的warn

{
  "generators": {
    "modules": {}
  },
  "hooks": {
    "grunt": false
  },
  "paths": {
    "views": "views"
  }

}

2、修改模板引擎配置

安装swig: 目录下,npm install swig

config/views文件:

engine: {
    'name': 'swig',
    'ext': 'html',
    fn: function (pathName, locals, cb) {
      var swig = require('swig')
      swig.setDefaults({ 
        loader: swig.loaders.fs('./views') 
      })
      return swig.renderFile(pathName, locals, cb);
    }
  },

3、简历 views和assets目录

assets目录: 

js

lib: for bower

img

font

css

 scss 或者less

==================================

4、安装bower

assets目录下 bower init

assets下目录static

.bowerrc:

{
  "directory": "./static/lib/",
  "analytics": false,
  "timeout": 120000
}

5、配置nginx静态目录和upstream

vhost 

6、配置安装gulp来适配当前view模式

assets目录下,设置bower和gulpfile.js

npm install安装时可能会有问题:

Error: pngquant failed to build, make sure that libpng-dev is installed

This error means that the system is lacking libpng development library, which is needed to installimagemin Node.JS module. To install it on CentOS 6, you need to issue this command:

yum install libpng-devel


另外简单介绍下assets/gulpfile.js中的babel配置,完整文件请戳到github上: https://github.com/xunuoi/sails-babel/blob/master/assets/gulpfile.js

通过配置来启用你想要的es6、7特性:

var babelOptional = [
    "es7.asyncFunctions",
    "es7.objectRestSpread",
    "es7.functionBind",
    "es7.comprehensions",
]

在gulp task中引用这个option:

gulp.task('es6', function() {
  return gulp.src([
      j(ASSETS_ROOT, 'es6/**/*.es6'), 
    ])
    .pipe(p.babel({
      optional: babelOptional,
    }))
    .pipe(gulp.dest(
      j(ASSETS_ROOT, '.tmp')
    ))
})



==========================================================================

前端构建中,涉及到配合es6中的import 语句(相当于烂大街的require等)来打包构建(browserify来构建),并且增加md5防止缓存问题,需要对一个gulp插件修改一下,这个插件是gulp-md5-plus,但是本身不支持文件搜索定位,所以修改下来支持,详细如下:

修改gulp-md5-plus ,增加root选项

module.exports = function (size, ifile, rootpath) {
size = size | 0;
rootpath = rootpath || '
xxx
})
        var match_file_path = path.join(rootpath, relativepath)
        var md5_filename = filename.split('.').map(function(item, i, arr){
            return i == arr.length-2 ? item + '_'+ d : item;
        }).join('.');
        var relative_dir = path.relative(file.base, dir)
        var md5_file_path = path.join(rootpath,relative_dir, md5_filename)
        console.log('debug: gulp-md5-plus: \n', md5_file_path)
        

然后替换replace:

replace(new RegExp(match_file_path), md5_file_path);


修改后的完整代码(安装完gulp-md5-plus,他的目录下index.js的代码):


var path = require('path')
, gutil = require('gulp-util')
, through = require('through2')
, crypto = require('crypto')
, fs = require('fs')
, glob = require('glob');
module.exports = function (size, ifile, rootpath) {
    size = size | 0;
    rootpath = rootpath || ''
    return through.obj(function (file, enc, cb) {
        if (file.isStream()) {
            this.emit('error', new gutil.PluginError('gulp-debug', 'Streaming not supported'));
            return cb();
        }
        if(!file.contents){
            return cb();
        }
        var d = calcMd5(file, size)
        , filename = path.basename(file.path)
        , relativepath = path.relative(file.base ,file.path)
        , sub_namepath = relativepath
        .replace(new RegExp(filename) , "").split(path.sep).join('/')
        , dir;
        if(file.path[0] == '.'){
            dir = path.join(file.base, file.path);
        } else {
            dir = file.path;
        }
        dir = path.dirname(dir);
        var match_file_path = path.join(rootpath, relativepath)
        var md5_filename = filename.split('.').map(function(item, i, arr){
            return i == arr.length-2 ? item + '_'+ d : item;
        }).join('.');
        var relative_dir = path.relative(file.base, dir)
        var md5_file_path = path.join(rootpath,relative_dir, md5_filename)
        console.log('debug: gulp-md5-plus: \n', match_file_path)
        console.log('debug: gulp-md5-plus: \n', md5_file_path)
        
        if(Object.prototype.toString.call(ifile) == "[object Array]"){
            ifile.forEach(function(i_ifile){
                i_ifile && glob(i_ifile,function(err, i_files){
                    if(err) return console.log(err);
                    i_files.forEach(function(i_ilist){
                        var result = fs.readFileSync(i_ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);
                        fs.writeFileSync(i_ilist, result, 'utf8');
                    })
                })
            })
        }else{
            ifile && glob(ifile,function(err, files){
                if(err) return console.log(err);
                files.forEach(function(ilist){
                    var result = fs.readFileSync(ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);
                    fs.writeFileSync(ilist, result, 'utf8');
                })
            })
        }
        file.path = path.join(dir, md5_filename);
        this.push(file);
        cb();
    }, function (cb) {
        cb();
    });
};
function calcMd5(file, slice){
    var md5 = crypto.createHash('md5');
    md5.update(file.contents, 'utf8');
    return slice >0 ? md5.digest('hex').slice(0, slice) : md5.digest('hex');
}


==========================================================================


关于 gulpfile.js

两个gulpfile。assets和根目录下各一个

browserify只能打包js,也就是转化成es5的js文件。通过添加paths这个函数,可以设置全局模块的路径,注意此时paths必须是转成js的模块,不是es6的路径。

部分打包代码:

function browserifyOne(fpath){
    return browserify({
          entries: fpath,
          debug: true,
          sourceMaps: false,
          extensions: ['.es6', '.jsx', '.js'],
          paths: [
            j(ASSETS_ROOT, 'lib'),
            j(ASSETS_ROOT, '.tmp/common')
          ]
      })
      /*.transform(babelify.configure({
        optional: babelOptional
      }))*/
      /*.require(require.resolve('babel/polyfill'),{expose: 'babel/polyfill'} )*/ // use regenerators
      .bundle()
      .pipe(source(fpath))
      .pipe(buffer())
      .pipe(p.rename(function(path) {
        path['dirname'] = path['dirname'].replace('.tmp', 'js').replace(j(ASSETS_ROOT,'/'), '')
      }))
      /*.on('error', function(err){
        throw Error(err)
      })*/
}

7、sails服务端启用es6

安装sails-babel-hook的钩子,自动调用babel转化,不需要再手工写gulp来转了

8、配置js和lib

让jquery能打包进入js中正常使用

//main.js

import 'jquery/dist/jquery'
$('body').html('i am jquery googog')
export { foo, bar }

修改jquery源代码

(function( global, factory ) {
	if (false && typeof module === "object" && typeof module.exports === "object" ) {

9、适配mongodb

npm install --save-dev sails-mongo

创建对应model