php 项目模块化,前端工程模块化——以一个php项目为例

实现一个页面功能总是需要 JavaScript、CSS 和 Template 三种语言相互组织,所以我们真正需要的是一种可以将 JavaScript、CSS 和 Template 同时都考虑进去的模块化方案。

前端模块化带来的性能问题

很多主流的模块化解决方案通过 JavaScript 运行时来支持“匿名闭包”、“依赖分析”和“模块加载”等功能,例如“依赖分析”需要在 JavaScript 运行时通过正则匹配到模块的依赖关系,然后顺着依赖链(也就是顺着模块声明的依赖层层进入,直到没有依赖为止)把所有需要加载的模块按顺序一一加载完毕, 当模块很多、依赖关系复杂的情况下会严重影响页面性能。

模块化为打包部署带来的极大不便

传统的模块化方案更多的考虑是如何将代码进行拆分,但是当我们部署上线的时候需要将静态资源进行合并(打包),这个时候会发现困难重重,每个文件里 只能有一个模块,因为模块使用的是“匿名定义”,经过一番研究,我们会发现一些解决方案,无论是“ combo 插件”还是“ flush 插件”,都需要我们修改模块化调用的代码,这无疑是雪上加霜,开发者不仅仅需要在本地开发关注模块化的拆分,在调用的时候还需要关注在一个请求里面加载哪 些模块比较合适,模块化的初衷是为了提高开发效率、降低维护成本,但我们发现这样的模块化方案实际上并没有降低维护成本,某种程度上来说使得整个项目更加 复杂了。

首先我们来看一下一个 web 项目是如何通过“一体化”的模块化方案来划分目录结构:

0d38ac6cda0a9aac498181b2d28f7122.png

站点(site):一般指能独立提供服务,具有单独二级域名的产品线。如旅游产品线或者特大站点的子站点(lv.baidu.com)。

子系统(module):具有较清晰业务逻辑关系的功能业务集合,一般也叫系统子模块,多个子系统构成一个站点。子系统(module)包括 两类: common 子系统, 为其他业务子系统提供规范、资源复用的通用模块;业务子系统:,根据业务、URI 等将站点进行划分的子系统站点。

页面(page): 具有独立 URL 的输出内容,多个页面一般可组成子系统。

模块(widget):能独立提供功能且能够复用的模块化代码,根据复用的方式不同分为 Template 模块、JS 模块、CSS 模块三种类型。

静态资源(static):非模块化资源目录,包括模板页面引用的静态资源和其他静态资源(favicon,crossdomain.xml 等)。

前端模块(widget),是能独立提供功能且能够复用的模块化代码,根据复用的方式不同分为 Template 模块、JS 模块、CSS 模块三种类型,CSS 组件,一般来说,CSS 模块是最简单的模块,它只涉及 CSS 代码与 HTML 代码; JS 模块,稍为复杂,涉及 JS 代码,CSS 代码和 HTML 代码。一般,JS 组件可以封装 CSS 组件的代码; Template 模块,涉及代码最多,可以综合处理 HTML、JavaScript、CSS 等各种模块化资源,一般情况,Template 会将 JS 资源封装成私有 JS 模块、CSS 资源封装成自己的私有 CSS 模块。下面我们来一一介绍这几种模块的模块化方案。

模板模块

我们可以将任何一段可复用的模板代码放到一个 smarty 文件中,这样就可以定义一个模板模块。在 widget 目录下的 smarty 模板(本文仅以 Smarty 模板为例)即为模板模块,例如 common 子系统的 widget/nav/ 目录

├── nav.css

├── nav.js

└── nav.tpl

下 nav.tpl 内容如下:

  • {$doc.title}

然后,我们只需要一行代码就可以调用这个包含 smarty、JS、CSS 资源的模板模块,

// 调用模块的路径为 子系统名称:模板在 widget 目录下的路劲

{widget name="common:widget/nav/nav.tpl" }

这个模板模块(nav)目录下有与模板同名的 JS、CSS 文件,在模板被执行渲染时这些资源会被自动加载。如上所示,定义 template 模块的时候,只需要将 template 所依赖的 JS 模块、CSS 模块存放在同一目录(默认 JavaScript 模块、CSS 模块与 Template 模块同名)下即可,调用者调用 Template 模块只需要写一行代码即可,不需要关注所调用的 template 模块所依赖的静态资源,模板模块会帮助我们自动处理依赖关系以及资源加载。

JavaScript 模块

上面我们介绍了一个模板模块是如何定义、调用以及处理依赖的,接下来我们来介绍一下模板模块所依赖的 JavaScript 模块是如何来处理模块交互的。我们可以将任何一段可复用的 JavaScript 代码放到一个 JS 文件中,这样就可以定义为一个 JavaScript 类型的模块,我们无须关心“ define ”闭包的问题,我们可以获得“ CommonJS ”一样的开发体验,下面是 nav.js 中的源码.

// common/widget/nav/nav.js

var $ = require(‘common:widget/jquery/jquery.js‘);

exports.init = function() {

...

};

我们可以通过 require、require.async 的方式在任何一个地方(包括 html、JavaScript 模块内部)来调用我们需要的 JavaScript 类型模块,require 提供的是一种类似于后端语言的同步调用方式,调用的时候默认所需要的模块都已经加载完成,解决方案会负责完成静态资源的加载。require.async 提供的是一种异步加载方式,主要用来满足“按需加载”的场景,在 require.async 被执行的时候才去加载所需要的模块,当模块加载回来会执行相应的回调函数,语法如下:

// 模块名: 文件所在 widget 中路径

require.async(["common:widget/menu/menu.js"], function( menu ) {

menu.init();

});

一般 require 用于处理页面首屏所需要的模块,require.async 用于处理首屏外的按需模块。

CSS 模块

在模板模块中以及 JS 模块中对应同名的 CSS 模块会自动与模板模块、JS 模块添加依赖关系,进行加载管理,用户不需要显示进行调用加载。那么如何在一个 CSS 模块中声明对另一个 CSS 模块的依赖关系呢,[email protected] 字段标记的依赖关系,这些分析处理对 html 的 style 标签内容同样有效,

/**

* demo.css

* @require reset.css

*/

非模块化资源

在实际开发过程中可能存在一些不适合做模块化的静态资源,那么我们依然可以通过声明依赖关系来托管给静态资源管理系统来统一管理和加载,

{require name="home:static/index/index.css" }

如果通过如上语法可以在页面声明对一个非模块化资源的依赖,在页面运行时可以自动加载相关资源。

项目实例

下面我们来看一下在一个实际项目中,如果在通过页面来调用各种类型的 widget,首先是目录结构:

├── common

│   ├── fis-conf.js

│   ├── page

│   ├── plugin

│   ├── static

│   └── widget

└── photo

├── fis-conf.js

├── output

├── page

├── static

├── test

└── widget

我们有两个子系统,一个 common 子系统(用作通用),一个业务子系统,page 目录用来存放页面,widget 目录用来存放各种类型的模块,static 用于存放非模块化的静态资源,首先我们来看一下 photo/page/index.tpl 页面的源码,

{extends file="common/page/layout/layout.tpl"}

{block name="main"}

{require name="photo:static/index/index.css"}

{require name="photo:static/index/index.js"}

demo 1

Button

{script type="text/javascript"}

// 同步调用 jquery

var $ = require(‘common:widget/jquery/jquery.js‘);

$(‘#btn‘).click(function() {

// 异步调用 respClick 模块

require.async([‘/widget/ui/respClick/respClick.js‘], function() {

respClick.hello();

});

});

{/script}

// 调用 renderBox 模块

{widget name="photo:widget/renderBox/renderBox.tpl"}

{/block}

第一处代码是对非模块化资源的调用方式;第二处是用 require 的方式调用一个 JavaScript 模块;第三处是通过 require.async 通过异步的方式来调用一个 JavaScript 模块;最后一处是通过 widget 语法来调用一个模板模块。 respclick 模块的源码如下:

exports.hello = function() {

alert(‘hello world‘);

};

renderBox 模板模块的目录结构如下:

└── widget

└── renderBox

├── renderBox.css

├── renderBox.js

├── renderBox.tpl

└── shell.jpeg

虽然 renderBox 下面包括 renderBox.js、renderBox.js、renderBox.tpl 等多种模块,我们再调用的时候只需要一行代码就可以了,并不需要关注内部的依赖,以及各种模块的初始化问题。

fis开源项目前端工程模块化: http://fex.baidu.com/blog/2014/03/fis-module/

原文:http://www.cnblogs.com/vanstrict/p/5700861.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于MyQEE MyQEE是一个开源、快速、优雅的轻量级PHP框架,支持HMVC模式,建立在PHP5.2基础之上,支持多项目管理开发,数据库内置自动主从分离功能,MySQL支持事务操作功能并且支持自动嵌套功能,多驱动设计灵活适应各种环境。点击访问 [MyQEE入门指引](./manual/guide/zh-cn/starting.md)。   拒绝粗糙不堪、复杂的代码,选择MyQEE,选择为WEB艺术家创造的PHP框架吧。   MyQEE PHP框架的特色 * MyQEE是一套轻量级的框架,但不是简陋的框架,系统具备完善的底层类库和强大的扩展功能设计; * 特有的 [HMVC](./manual/guide/zh-cn/hmvc.md) (分层MVC设计)和多项目支持,开发更灵活; * 支持时下最流行的PHP包管理器 [Composer](http://getcomposer.org/) ,并且可以使用 Composer 安装 MyQEE 提供的官方类库; * 代码一致性设计:例如 `MySQL` 和 `MongoDB` 的查询语句完全不同,但是在 MyQEE 里可以做到实现90%的一致性,你的代码既可以使用在 `MySQL` 的环境里也可以用在 `MongoDB` 上; * 包括`Database`, `Cache`, `HttpClient`, `Session`, `Storage`, `Upload` 等支持多驱动,可以适应不同环境的需求,其中数据库支持 `MySQL`, `MySQLI`, `Mongo`, `SQLite`, `Postgre`,缓存支持 `Memcache`, `File`, `Redis`, `Apc`, `Database`, `SQLite`, `WinCache` 等; * 数据库提供强大的 `QueryBuilder` 功能,可实现同相同程序兼容多种数据库,解决SQL注入隐患和迁移环境后顾之忧; * 云引擎支持:支持SAE和BAE等云引擎,MyQEE网站就运行在SAE上; * 高性能和优雅的代码:经测试 MyQEE 的初始化速度比 Codeigniter 等优秀的轻量级框架还快; * 完备和详细的文档和API支持,更可简单的生成自己的团队文档; * 为团队开发而生,特别提供团队类库功能,多项目设置可以帮助团队成员之间规划独立和共用的代码; * ORM支持,提供了特有的高性能ORM; * 支持 `RESTFul`,支持 [PHPRPC](http://www.phprpc.org/); * 独创5模式运行设计:普通控制器、后台、命令行、系统调用、RESTFul的控制器相互分离,系统更加安全可靠;   安全性 * 系统内置XSS安全过滤; * 防SQL注入,强大的QueryBuilder; * 强制数据类型转换; * 普通控制器、后台、命令行、系统调用、RESTFul 5种运行模式相互隔离,安全更有保障;   MyQEE v3.0 RC2 更新日志: 本次更新在3.0RC1的基础上做了一些完善,修复了一些Bug: 完善文档生成脚本 完善模块化的拆分 数据库增加对 group_concat 的支持,MongoDB数据库驱动支持在group查询中使用distinct查询,修复MongoDB驱动力中查询slave在新的版本里可能导致连接失败的问题 增加 BigInt 类库 日期类库完善 HttpClient 增加upload方法,可实现上传文件功能 完善邮件类库,修复 Email 中上传附件bug,支持收件人姓名 邮件的格式,完善密件抄送的功能 Session 类库优化 Swift Storage 驱动完善,token验证支持v1和v2版本,优化参数传送方式,支持url方式的配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值