最近我转组到一个之前没有前端的一个项目组,然后由偏后端的rd来开发全端。 弊病是:

  1. 样式乱七八糟

  2. js效率低下

  3. 开发代码即为发布代码

    1)为了压缩代码,他们是每次写完前端代码手动去掉换行和空格符。浪费劳动力加前端代码无法code review和版本管理。

    2)css和js和view相关代码分别放至于不同的路径。相关的js、css和html没有放置在一起,开发时成本加高,组件化难度大。

既然作为这个组唯一的前端,我毅然决然决定必须重构,而因为我们组用的是php框架yii1。而fisp(百度基于PHP的前端工程化构建工具解决方案)只要为yii1增加smarty的扩展(接入方法见附录2),就可以简单切入了。而且fisp的好处如下:

1. 前后端分离,前端开发和发布分离

2. 组件化,增高代码复用性,并且结构清晰,也易于理解、学习和使用

fisp项目的文件结构:

fisp project

  • fis-conf.js: 项目配置文件

    • 开发和部署都相关: 合并压缩优化相关配置
    • 开发相关:配置receiver.php路径和相应的项目文件在测试机上的存储位置
    • 部署相关操作用: fisp本地发布和copy操作(可放入脚本)
  • page:页面文件
    • 标签
      • html主要tag:html head body
      • 自定义块: block
      • 引入css和js文件的标签 require 发布后会吧css在head中引入,js在底部引入,而css与css之间,js和js之间的顺序保持不变
      • 内嵌js代码标签 script
      • 组件引入文件 widget
    • 一般引入文件的定义为:
      • name="{namespace}:域名下的开发路径"
      • 只用专注于开发路径,发布路径由fis-conf配置,会生map文件对应相应name的发布路径和它所依赖的模块
    • layout.tpl 整体布局文件,定义好每个页面的相同处,比如引入公用样式,公用js
  • widget:组件文件
  • static:静态资源
  • server.conf: 用于本地测试时路径配置
  • test: 测试数据的php文件,根据page中的页面区分

    fisp test data


3. 自动化,代码压缩、合并,图片压缩、雪碧图,发布预览自动化

通过fisp release指令可以轻松完成部署
部署主要分为本地部署和远程部署,由-d或者–dest配置:

1) 如果-d是一个目录,则会发布到相应的目录,例如:

fisp release -d ../output // 发布到你执行这条指令的位置的兄弟目录output中

2) 如果-d是你在fisp-conf.js里配置的deploy,则会发步到相应机器,至于如何配置见下文fis-conf.js代码和相关备注

注意远程发布的机器上要部署reciever.php,代码示例 为了安全,以上部署方式最好只用于安全域内的开发机使用,至于线上服务器的发布,我们建议用本地发布,然后cp指令将发布目录中的config,template和static目录复制到相应位置,举例:

#!/bin/sh
root_dir='XXX' #项目根目录
cd $root_dir/FEproject #前端项目目录
svn up
fisp release -omp -r ./common -d ./output
cp -rf ./output/config/* ../protected/config/
cp -rf ./output/template/* ../protected/views/
cp -rf ./output/XXX/* ..
rm -rf output
fisp release参数详解
指令说明
-rfisp项目(拥有fis-conf.js的目录)
-d | --dest指定目录或者是你配置的远程发布
-c清理缓存
-o优化
-p | --pack 打包
-m | --md5md5后缀
-w | --watch持续监视文件修改,除了fis-conf.js的修改其他前端修改会实时重新发布






附录1 fis-conf.js例子(我的修改:自定义static资源放置目录;远程发布deploy配置简化)

// 此处为了方便多个用户添加发布配置而做的修改
var webroot = {
    fangsimin: {
        "receiver": 'http://XXX/receiver.php', // 你的机器部署的reciever.php的url
        "root": "", // 你的项目的根目录
        "static_url": '/dev/assets/' // 修改静态资源发布路径的源目录
    },
    // 每个新机器只需添加一个类似前面fangsimin那样的配置
};
var RELEASE_MACHINE_CONFIG = (function() {
    var ret = {};
    for (i in webroot) {
        ret[i] = {
            // 你的机器部署的reciever.php的url
            receiver: webroot[i]['receiver'], 
            // 相关配置发布路径
            smarty_plugin: webroot[i]['root']+'protected/extensions/smarty/plugins',
            smarty_config: webroot[i]['root']+'protected/config/',
            template_dir: webroot[i]['root']+'protected/views/',
            static_dir: webroot[i]['root']+'assets/',
        }
    };

    return ret;
})();
// 此处为了配置fis.config中的static配置时使用,拿到的是 fisp release指令的-d的参数
var target = fis.cli.commander.args[0].dest;
//禁止模板xss优化
fis.config.set('modules.optimizer.tpl', '');
fis.config.set('modules.prepackager', fis.config.get('modules.prepackager') + ', widget-inline');
fis.config.merge({
    namespace: 'common',
    // 此处配置的是html,css和js中的相应静态资源的路径替换
    statics: webroot[target]?webroot[target]['static_url']:'/dev/assets/',
    settings: {
        spriter: {
            csssprites: {
                margin: 10
            }
        },
        prepackager: {
            'widget-inline':  {
                include: /.*/i,
                exclude: /(widget_a|widget_b|widget_c|widget_d)/
            }
        }
    },

    // 合成雪碧图
    modules: {
        spriter: 'csssprites',
    },

    // 打包配置
    pack: {
        // 所有页面公用模块
        '/pkg/common.js': [
            '/static/common/mod.js',
            '/static/common/jquery.js',
            '/static/common/jquery.cookie.js',
            '/static/common/util.js',
            '/static/common/template-native-debug.js',
            '/static/common/bootstrap/js/bootstrap.js',
            '/static/common/template-native-debug.js',
            '/widget/popup/popup.js'
        ],
        '/pkg/common.css': [
            '/static/common/font-awesome/css/font-awesome.min.css',
            '/static/common/bootstrap/css/bootstrap.css',
            '/static/common/font-awesome/css/font-awesome.min.css',
            '/static/common/common.css',
            '/widget/popup/popup.less'
        ],
        ...
    },

    // 部署配置,此处外包函数执行循环方便我们通过前面设置的变量webroot来配置多个用户的发布配置
    // 其实最后deploy就是一个object,其中key为你之后用fisp release的-d参数,value为相应的相应的发布对应地址。
    // 具体可以参见fisp官网的deploy配置的例子
    deploy: (function() {
        var ret = {};
        for (i in webroot) {
            ret[i] = [
                {
                    receiver: RELEASE_MACHINE_CONFIG[i].receiver,
                    from: '/plugin',
                    subOnly: true,
                    to: RELEASE_MACHINE_CONFIG[i].smarty_plugin,
                },
                {
                    receiver: RELEASE_MACHINE_CONFIG[i].receiver,
                    from: '/config',
                    subOnly: true,
                    to: RELEASE_MACHINE_CONFIG[i].smarty_config,
                },
                {
                    receiver: RELEASE_MACHINE_CONFIG[i].receiver,
                    from: '/template',
                    subOnly: true,
                    to: RELEASE_MACHINE_CONFIG[i].template_dir,
                },
                {
                    receiver: RELEASE_MACHINE_CONFIG[i].receiver,
                    // 此处不同于常规配置,是因为我们的项目定义的静态资源路径与fisp原来的'/static'目录
                    // 为了静态资源路径替换的正常而修改的配置
                    from: webroot[i]['static_url'],
                    subOnly: true,
                    to: RELEASE_MACHINE_CONFIG[i].static_dir,
                }];
        };
        return ret;
    })()
});




附录2 yii1加入smarty扩展

  1. 去smarty官网下载smarty
  2. 将下载包解压复制其中的lib到protected/extensions/smarty
  3. 在protected/extensions/smarty创建CSmarty.php
<?php
/**
 * 扩展增加smarty模板 
 *
 * @author Hema
 * @link http://www.ttall.net/
 * @copyright Copyright © 2012-2015  ttall.net
 * @license http://www.ttall.net/license/
 */
Yii::import("application.extensions.*");
require_once (Yii::getPathOfAlias('application.extensions.smarty') . DIRECTORY_SEPARATOR . 'Smarty.class.php');
// 配置模板目录和配置目录
define('SMARTY_VIEW_DIR', Yii::getPathOfAlias('application.views'));
define('SMARTY_CONFIG_DIR', Yii::getPathOfAlias('application.config'));
class CSmarty extends Smarty {
	const DIR_SEP = DIRECTORY_SEPARATOR;
	function __construct() {
		parent::__construct();
		$this -> template_dir = SMARTY_VIEW_DIR;
		$this -> compile_dir = SMARTY_VIEW_DIR . self::DIR_SEP . 'template_c';
		$this -> caching = false;
		$this -> cache_dir = SMARTY_VIEW_DIR . self::DIR_SEP . 'cache';
		$this -> config_dir = SMARTY_CONFIG_DIR;
		$this -> cache_lifetime = 0;
		$this -> error_reporting = E_ALL & ~E_NOTICE; // smarty会报一些无关紧要的warning,故屏蔽掉
	}
	function init() {
	}
}

然后在配置文件main.php中配置CSmarty CSmarty