基于fis的前端模塊化和工程化方案

jopen 8年前發布 | 48K 次閱讀 HTML FIS 前端技術

前端構建工具

面對日益復雜的前端環境以及前端技術、node技術的高速發展,前端的開發也越來越工程化,體系化,也就是出現了前端自動化構建工具。他們完成的任務目標基本是:

  • js,css,圖片的自動壓縮合并(圖片也即是是自動sprite)
  • js,css,圖片自動添加域名
  • js,css,圖片自動添加md5或版本號
  • 自動監聽文件變化
  • sass/less/coffee等的自動編譯
  • 支持amd/cmd的模塊開發,可自動文件依賴
  • 可以部署文件
  • 網頁自動刷新
  • 實時編譯

成熟的前端構建工具也有很多,比如:Gulp.js,Grunt,webpark, fis等等,其他構建工具本人使用不多,本文主要是對fis的前端工程化和模塊化的使用做詳細介紹

關于fis

fis是百度研發的一套前端構建工具,擁有豐富的腳手架和組件倉庫。因為fis是本人接觸的最早的前端構建工具,所以一直沿用到了至今。

    注: 本文是針對fis2,基于fis3的配置和插件將在稍后給出

fis的前端工程化和模塊化基礎插件

1.自動打包合并插件

fis配置

//開始autoCombine可以將零散資源進行自動打包
fis.config.set('settings.postpackager.simple.autoCombine', true);
//開啟autoReflow使得在關閉autoCombine的情況下,依然會優化腳本與樣式資源引用位置
fis.config.set('settings.postpackager.simple.autoReflow', true);
fis.config.set('settings.postpackager.simple.output', 'pkg/mcren_${hash}');

作用

將html中分散的靜態資源進行自動合并打包

應用舉例:

原始文件

  <link rel="stylesheet" type="text/css" href="/css/mcren.css">
  <link rel="stylesheet" type="text/css" href="/site/index/index/index.css">

轉換后

   <link type="text/css" rel="stylesheet" href="/pkg/mcren_7636e.css">

可以看到fis會自動合并多個css到同一個文件里,這個合并不僅僅適用于css,也同樣適用與js,并且將自動把css文件放入header頭,js放在body結束前,有了這個功能也就具備的模塊化開發的大前提

fis的include功能

fis配置

默認支持,無須插件

作用

大家在使用模板的時候,肯定是少不了include功能的, 即公共部分的文件引用。fis同樣支持這個功能,而且借助與自動打包功能,include功能的作用也被放大的很多.(fis支持多級include)

應用舉例

主模板文件

<!DOCTYPE html>
<html>

<head>
  <meta name="description" content="">
  <meta name="keywords" content="">
  <link rel="stylesheet" type="text/css" href="/css/mcren.css">
  <link rel="stylesheet" type="text/css" href="/site/index/index/index.css">
  <script type="text/javascript" src="/lib/mod.js"></script>
</head>

<body>
  <link rel="import" href="/widget/header-small/header.html?__inline">

次模版文件(header-small/header.html)

<link rel="stylesheet" type="text/css" href="header.css">
<div class="header">
    <div>
        <link rel="import" href="../loginstate/loginstate.html?__inline"><h1><a href="/">主頁</a></h1>
    </div>
</div>
<script type="text/javascript">
    var jsfunc = require('jsfunc/jsfunc');
    jsfunc.init();
</script>

轉換后

<!DOCTYPE html>
<html>

<head>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link type="text/css" rel="stylesheet" href="/pkg/mcren_7636e.css">
</head>

<body>
    <div class="header">
      <div>
          <div class="loginstate">
            <a href="/space">左鹽</a> | <a href="javascript:void(0);">退出</a><img src="member.jpg" id="avatar" />
          </div>
           <h1><a href="/">名場</a></h1>
       </div>
    </div>

    <!--省略的html代碼-->

<script type="text/javascript" src="/lib/mod.js"></script>
<script type="text/javascript">
    var jsfunc = require('jsfunc/jsfunc');
    jsfunc.init();
</script>
</body>

說明

可以看到,經過fis處理后,本來應該分散的css被組合放進了head頭里,js被放在了body結束前,模板的html代碼也正常引入了進去。

另外大家可以看到我模塊的劃分,header模塊的html是引入css的,也就是說模塊與模塊之間以及模塊和主體頁面之間的css都是獨立的,這樣充分解耦,可以有效的解決css的維護問題,

圖片雪碧

fis配置

fis.config.set('modules.spriter', 'csssprites');

作用

自動把css中的圖片轉換成雪碧圖

應用舉例

不寫了,大家都懂的

ejs分析能力

fis配置

//tell fis that `.ejs` is a js file 
fis.config.set('roadmap.ext.ejs', 'js');
//tell fis that parse `.ejs` file by using `fis-parser-ejs` plugin 
fis.config.set('modules.parser.ejs', 'ejs');

作用

大家知道,寫js打印html字符串到頁面的時候,如果在js里面串接html字符串是一種很難受的體驗,所以fis也就有了這個插件,這個插件可以給js方法添加引用ejs模板的能力,這里ejs的使用方法和原生的完全兼容

應用舉例

js函數

function ejsEx() {
    var tpl = __inline('comment.ejs');
    var s = tpl({
        title: "我的ejs模板"
    });
    console.log(s);
}

ejs模板

<h1><%= title%></h1>

輸出

<h1>我的ejs模板</h1>

目錄結構

上面已經介紹了fis的模塊化基礎能力,現在開始實踐fis的模塊化開發能力。當然fis的amd/cmd,域名添加等等基礎功能,這里沒有敘述,您可以自行上官網查看學習

根目錄

css //less生成的css文件

font //字體圖標文件

img //公共圖片

less

lib //系統類庫

modules //常用的module

jquery

laydate

layer

pizzalayer

pizzatools //網站工具類

pizzaui //ui組件

store //本地化插件

xss //xss過濾插件

site //非模塊的css,js

views //網頁模板文件

widget //模塊

head //頭部模塊

footer //底部模塊

nav //菜單模塊

fis-conf.js //fis配置文件

因為我的技術構架是: 前端 + nodejs + api,所以使用這種目錄結構,用戶可根據自己的項目目錄自由更改。

說明

modules目錄

modules都是工具類,只包含js,目錄結構為:

---根目錄
----modules
-----jquery
------jquery-1.11.3.min.js

引用方式為:require('文件夾名字')

require('jquery')

widget目錄

widget目錄都是網站模塊,可包含js,css,html,圖片目錄結構為:

---根目錄
----widget
-----loginstate
------loginstate.less
------loginstate.js
------loginstate.html
------loginstate.jpg

引用方式為:

<link rel="import" href="/widget/loginstate/loginstate.html?__inline">

一個模塊的代碼示例

loginstate.html代碼

<link rel="stylesheet" type="text/css" href="loginstate.css">
<div class="loginstate">
    <a href="/space">左鹽</a> | <a href="javascript:void(0);">退出</a><img src="member.jpg" id="avatar" />
</div>
<script type="text/javascript">
    var loginstate = require('loginstate/loginstate');
    loginstate.init();
</script>

loginstate.js代碼

var $  = require('jquery');
var tools = require('pizzatools');
require('pizzalayer');
var loginState = new function() {
    var _self = this;
    /**
     * 打印登錄狀態
     * @return {[type]} [description]
     */
    _self.init = function() {
        var s = '';
        var id = tools.getCookie('id');
        if(id == '0' ) {//未登錄
            s = '<a href="/login?f='+document.location.href+'" class="btn btn-primary">登錄</a>    <a href="/reg" class="btn btn-primary">注冊</a>';
        }
        else {
            s = '<a href="/space">' + tools.getCookie('nickname') + '</a> | <a href="javascript:void(0);" onclick="loginstate.loginout();">退出</a><img src="' + tools.siteData.url.avatar + tools.getCookie('avatar') + '!v1" id="avatar" />';
        }
        $('.loginstate').html(s);
    }
    /**
     * 退出登錄
     * @return {[type]} [description]
     */
    _self.loginout = function() {
        $.ajax({
            type:'GET',
            url:'/index/loginout',
            success: function(msg) {
                var url = document.location.href.split('/');
                if(url[3] == 'space') {
                    document.location.href = '/';
                }
                else {
                    document.location.reload();
                }
            }
        })
    }
}
module.exports = loginState;

index.html代碼

<div class="header">
    <div>
        <link rel="import" href="/widget/loginstate/loginstate.html?__inline"><h1><a href="/">主頁</a></h1>
    </div>
</div>

由此前端模塊化已經全部完成

所需插件

  • fis-postprocessor-require-async
  • fis-parser-ejs
  • fis-postpackager-autoload
  • fis-postpackager-simple
npm install 以上插件即可

fis-conf.js

結合我的項目,本人的配置文件如下。下載本配置文件并且安裝好fis后,可以直接使用。(由于項目發展時間很長,配置文件已經顯得啰嗦,如果大拿研究了fis,可自行優化自己的配置文件)

fis.config.set('livereload.port', 8136);
//use css sprites
fis.config.set('modules.spriter', 'csssprites');
//tell fis that `.ejs` is a js file 
fis.config.set('roadmap.ext.ejs', 'js');
//tell fis that parse `.ejs` file by using `fis-parser-ejs` plugin 
fis.config.set('modules.parser.ejs', 'ejs');
//set options if you need 
//@see https://github.com/visionmedia/ejs#options 
fis.config.set('settings.parser.ejs', {
    open: '<%',
    close: '%>'
});
//使用simple插件,自動應用pack的資源引用
fis.config.set('modules.postpackager', 'simple');
//開始autoCombine可以將零散資源進行自動打包
fis.config.set('settings.postpackager.simple.autoCombine', true);
//開啟autoReflow使得在關閉autoCombine的情況下,依然會優化腳本與樣式資源引用位置
fis.config.set('settings.postpackager.simple.autoReflow', true);
fis.config.set('settings.postpackager.simple.output', 'pkg/mcren_${hash}');

fis.config.merge({
    pack: {
        'pkg/base.js': ['/modules/jquery/*.js', '/modules/layer/*.js', '/modules/pizzalayer/*.js', '/modules/pizzatools/*.js'],
        'pkg/kindeditor.js': ['/widget/kindeditor/kindeditor-min.js']
    }
});

fis.config.merge({
    statics: '/public',
    modules: {
        postprocessor: {
            js: "jswrapper, require-async",
            html: "require-async"
        },
        postpackager: ['autoload', 'simple'],
        lint: {
            js: 'jshint'
        }
    },
    roadmap: {
        ext: {

        },
        path: [{
            reg: /^\/modules\/laydate\/(need|skins)\/.*\.(js|css|png|gif)$/i,
            useHash: false,
            isMod: false,
            release: '${statics}/$&',
            url: '$&'

        }, {
            reg: /^\/widget\/kindeditor\/(lang|plugins|themes)\/.*\.(js|css|png|gif)$/i,
            useHash: false,
            isMod: false,
            release: '${statics}/$&',
            url: '$&'

        }, {
            reg: /^\/lib\/(.*)\.(js)$/i,
            isMod: false,
            release: '${statics}/$&',
            url: '/lib/$1'
        }, {
            reg: /^\/font\/(.*)$/i,
            isMod: false,
            release: '${statics}/$&',
            url: '/font/$1'
        }, {
            reg: /^\/views\/(.*)$/i,
            useCache: false,
            release: '/views/$1'
        }, {
            //一級同名組件,可以引用短路徑,比如modules/jquery/juqery.js
            //直接引用為var $ = require('jquery');
            reg: /^\/modules\/([^\/]+)\/(.*)\.(js)$/i,
            //是組件化的,會被jswrapper包裝
            isMod: true,
            //id為文件夾名
            id: '$1',
            release: '${statics}/$&',
            url: '$0'
        }, {
            //組件化的webpart的js
            reg: /^\/(widget|site)\/(.*)\.(js)$/i,
            isMod: true,
            id: '$2',
            release: '${statics}/$&',
            url: '$&'
        }, {
            //modules目錄下的其他腳本文件
            reg: /^\/modules\/(.*)\.(js)$/i,
            //是組件化的,會被jswrapper包裝
            isMod: true,
            //id是去掉modules和.js后綴中間的部分
            id: '$1',
            release: '${statics}/$&',
            url: '/modules/$1'
        }, {
            //組件化的webpart的html
            reg: /^\/widget\/(.*)\.(html)/i,
            release: false
        }, {
            //組件化的webpart的css
            reg: /^\/(widget|site)\/(.*)\.(css|png|jpg)/i,
            release: '${statics}/$&',
            useSprite: true,
            url: '$&'
        }, {
            //其他css文件
            reg: /^(.*)\.(css|less)$/i,
            release: '${statics}/$&',
            url: '$&'
        }, {
            //前端模板
            reg: '**.ejs',
            //當做類js文件處理,可以識別__inline, __uri等資源定位標識
            isJsLike: true,
            //只是內嵌,不用發布
            release: false
        }, {
            reg: "map.js",
            release: "${statics}/"
        }, {
            reg: /.*\.(html|jsp|tpl|vm|htm|asp|aspx|php)$/,
            useCache: false,
            release: '${statics}/$&'
        }, {
            reg: "**",
            release: '${statics}/$&',
            url: '$&'
        }]
    },
    settings: {
        postprocessor: {
            jswrapper: {
                type: 'amd'
            }
        },
        lint: {
            jshint: {
                camelcase: true,
                curly: true,
                eqeqeq: true,
                forin: true,
                immed: true,
                latedef: true,
                newcap: true,
                noarg: true,
                noempty: true,
                node: true
            }
        }
    }
});

fis.config.merge({
    roadmap: {
        //所有靜態資源文件都使用 http://s1.example.com 或者 http://s2.example.com 作為域名
        domain: 'http://static1.example.com, http://s2.example.com'
    }
});


fis.config.merge({
    project: {
        exclude: /.docx|.bak$|.bat$|.md$|.rar$$|^\/less\/*|.less$|^\/modules\/pizzaui\/pizzaui\/*/i
    } //排除壓縮包,文檔,和bak文件
});

來自: http://www.cnblogs.com/spnt/p/5112705.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!