html与js模块化解决方案##
html 模块以预编译的方式模块编写,例:界面包含三部分(head body footJS同一套项目里面必然会涉及到通用的部分(head footJs),各个界面不同主要在body体。
js 以模块预加载的方式通过特定的方式去加载模块js代码。模块化js主要以sea.js方式去加载。
项目初始化
- 执行以下命令
$ npm install
注:可以通过cnpm安装
- 构建项目
$ gulp
目录结构
/project/
/dist # 最终输出和使用的代码目录
/js # 最终输出编译后的js文件
/css # 最终输出的样式文件
x.html # 输出html文件
/src # 源文件目录
/scss # scss源文件目录
/js # js源文件目录
/html # html源文件目录
模块讲解
1.html模块
html构建方式:
gulp.task("html", function() {
var distPath = './dist';
return gulp.src('src/html/*.html')
.pipe(includer({ debug : true}))
.pipe(replace("{{version}}", dateFormat('YmdHis')))
.pipe(htmlmin( { collapseWhitespace : true, minifyCSS : true, minifyJS : true }))
.pipe(gulp.dest(distPath))
.pipe(notify({ message: "HTML task complete!" }))
});
配置的解决方案:html模板之间主要以include的方式加载所需模块。类似于tmodJS(artTemplate),压缩html代码最终输出到dist文件中。模块加载方式(例):
<!-- include "./components/html_head.html" -->
<title>架手架编译html</title>
</head>
<body>
<div id="layout">
<!-- include "./components/header.html" -->
<div id="main">
中间内容层
</div>
<!-- include "./components/footer.html" -->
</div>
<div id="load-module" data-main="p.index"></div>
<!-- include "./components/global_js.html" -->
</body>
</html>
2. js模块化
在申明之前,先简单了解下html 模块中footJs模块的定义:
<script type="text/javascript" src="js/sea.js"></script>
<script>
var VERSION = "{{version}}";
seajs.config({
base : "./js/",
alias : {
"jquery" : (!window.addEventListener) ? "jquery-1.11.3.min.js" : "jquery-2.2.4.min.js"
},
preload: ['jquery'], //使用use之前确保模块已经加载好
'map': [
[ /^(.*\/js\/(.*)(js|css))(.*)$/i, "$1?v=" + VERSION]
]
});
seajs.use('app.min', function() {
seajs.use('app');
});
</script>
VERSION主要配置版本号,做文件加载禁止缓存处理,map中的映射主要是为了加载模块时,添加文件后缀禁止缓存。加载编译后的app.min.js。界面的入口函数都在app.js模块中去控制。那么,如何控制每个界面加载不同的js模块?先看app.js模块定义:
/**
* 初始化脚本模块文件
*/
define(function(require, exports, module) {
var $ = require("jquery"),
WD = require("widget");
$(function(){
var $loadModule = $('#load-module'),
loadModule = $loadModule.attr('data-main');
console.log('app.js 初始化脚本模块文件');
if (loadModule) {
require(loadModule); // 动态加载页面模块文件
}
});
});
所有界面的入口执行函数都在app.js中通过获取html每个界面body模板中定义的data-main中的参数动态加载相应的界面以来文件。例如上述例子中定义的data-main="p.index"
在界面开始执行入口主函数app.js后,会加载p.index.js模块。再看p.index模块定义:
/**
* 首页脚本模块文件
*/
define(function(require, exports, module) {
var $ = require('jquery');
var WD = require('widget');
console.log('p.index', WD);
console.log($);
....
var dialog = new WD.dialog();
});
在界面js模块中引入组件模块,业务模块,视图模块,控制模块。执行主函数。其中,每个模块都可以以模块化的方式定义,具体情景看具体的业务定义,以组件模块定义为例:
定义dialog组件
/**
* 一个对话框组件模块
*/
define(function(require, exports, module) {
function Dialog() {
console.log('Dialog');
}
module.exports = Dialog;
});
再接着定义全局模块引入所以定义好的组件模块
/**
* 公共组件模块文件的模块集合
*/
define(function(require, exports, module) {
var dialog = require('./mt.dialog'); // 例:引入一个对话框组件模块
exports.dialog = dialog;
//.... 其它组件模块
exports.func1 = function() {
alert('方法1');
};
});
在这个组件模块集合中,将所有模块暴露出去。具体调用方式,上述p.index.js模块中有定义。
构建亮点介绍
- 动态的js,css版本控制VERISON
- html模板模块划分。
- 模块化js脚本,更简洁明了的管理js代码
缺陷与不足
- 图片资源文件没有做处理。
- 低版本兼容性没处理(后期再做介绍)
- 将sea升级为es6语法
总结
此篇与前面两篇scss构建相呼应,可以将scss编译集成到项目里面。其中每个界面的执行脚本,主要通过界面核心(body)模板中声明的data-mian控制加载。以及编译后,动态修改界面引入的js与css文件的版本。有效解决在开发时,重复编译造成的缓存问题。至于此方案中优化的问题(兼容性控制,子模块定义方式,通用模块定义),文章另做详解