前端工程之模块化
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块化是一种处理<span style="color: black;">繁杂</span>系统分解<span style="color: black;">作为</span>更好的可管理模块的方式,它<span style="color: black;">能够</span>把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将<span style="color: black;">怎样</span>影响其它部分就会变得显而易见,系统的可<span style="color: black;">守护</span>性更加简单易得。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">前端<span style="color: black;">研发</span><span style="color: black;">行业</span>(JavaScript、CSS、Template)并<span style="color: black;">无</span>为<span style="color: black;">研发</span>者们<span style="color: black;">供给</span>以一种简洁、有条理地的方式来管理模块的<span style="color: black;">办法</span>。CommonJS(致力于设计、规划并标准化 JavaScript API)的诞生开启了“ JavaScript 模块化的时代”。CommonJS 的模块提案为在服务器端的 JavaScript 模块化做出了很大的贡献,<span style="color: black;">然则</span>在浏览器下的 JavaScript 模块应用<span style="color: black;">特别有</span>限。随之而来又诞生了其它前端<span style="color: black;">行业</span>的模块化<span style="color: black;">方法</span>,像 requireJS、SeaJS 等,然而这些模块化<span style="color: black;">方法</span>并不是<span style="color: black;">非常</span>适用 ,并<span style="color: black;">无</span>从<span style="color: black;">基本</span>上<span style="color: black;">处理</span>模块化的问题。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">前端模块化并不等于 JavaScript 模块化</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">前端<span style="color: black;">研发</span>相对其他语言<span style="color: black;">来讲</span>比较特殊,<span style="color: black;">由于</span><span style="color: black;">咱们</span>实现一个页面功能总是<span style="color: black;">必须</span> JavaScript、CSS 和 Template 三种语言相互组织才行,<span style="color: black;">倘若</span>一个功能仅仅<span style="color: black;">仅有</span> JavaScript 实现了模块化,CSS 和 Template 还是<span style="color: black;">处在</span>原始状态,那<span style="color: black;">咱们</span>调用这个功能的时候并<span style="color: black;">不可</span>完全<span style="color: black;">经过</span>模块化的方式,<span style="color: black;">那样</span><span style="color: black;">这般</span>的模块化<span style="color: black;">方法</span>并不是完整的,<span style="color: black;">因此</span><span style="color: black;">咱们</span>真正<span style="color: black;">必须</span>的是一种<span style="color: black;">能够</span>将 JavaScript、CSS 和 Template <span style="color: black;">同期</span>都<span style="color: black;">思虑</span>进去的模块化<span style="color: black;">方法</span>,而非仅仅 JavaScript 模块化<span style="color: black;">方法</span>。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">JavaScript 模块化并不等于异步模块化</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">主流的 JavaScript 模块化<span style="color: black;">方法</span>都<span style="color: black;">运用</span>“异步模块定义”的方式,这种方式给<span style="color: black;">研发</span>带来了<span style="color: black;">极重</span>的<span style="color: black;">不方便</span>,所有的同步代码都<span style="color: black;">必须</span>修改为异步的方式,<span style="color: black;">咱们</span><span style="color: black;">是不是</span><span style="color: black;">能够</span>在前端<span style="color: black;">研发</span>中<span style="color: black;">运用</span>“ CommonJS ”的方式,<span style="color: black;">研发</span>者<span style="color: black;">能够</span><span style="color: black;">运用</span>自然、容易理解的模块定义和调用方式,不<span style="color: black;">必须</span>关注模块<span style="color: black;">是不是</span>异步,不<span style="color: black;">必须</span>改变<span style="color: black;">研发</span>者的<span style="color: black;">研发</span><span style="color: black;">行径</span>。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">前端模块化带来的性能问题</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">非常多</span>主流的模块化<span style="color: black;">处理</span><span style="color: black;">方法</span><span style="color: black;">经过</span> JavaScript 运行时来支持“匿名闭包”、“依赖分析”和“模块加载”等功能,例如“依赖分析”<span style="color: black;">必须</span>在 JavaScript 运行时<span style="color: black;">经过</span>正则匹配到模块的依赖关系,<span style="color: black;">而后</span>顺着依赖链(<span style="color: black;">亦</span><span style="color: black;">便是</span>顺着模块声明的依赖层层进入,直到<span style="color: black;">无</span>依赖为止)把所有<span style="color: black;">必须</span>加载的模块按<span style="color: black;">次序</span>一一加载完毕,当模块<span style="color: black;">非常多</span>、依赖关系<span style="color: black;">繁杂</span>的<span style="color: black;">状况</span>下会严重影响页面性能。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">模块化为打包<span style="color: black;">安排</span>带来的<span style="color: black;">极重</span><span style="color: black;">不方便</span></h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">传统的模块化<span style="color: black;">方法</span><span style="color: black;">更加多</span>的<span style="color: black;">思虑</span>是<span style="color: black;">怎样</span>将代码进行拆分,<span style="color: black;">然则</span>当<span style="color: black;">咱们</span><span style="color: black;">安排</span>上线的时候<span style="color: black;">必须</span>将静态资源进行合并(打包),这个时候会<span style="color: black;">发掘</span>困难重重,<span style="color: black;">每一个</span>文件里只能有一个模块,<span style="color: black;">由于</span>模块<span style="color: black;">运用</span>的是“匿名定义”,经过一番<span style="color: black;">科研</span>,<span style="color: black;">咱们</span>会<span style="color: black;">发掘</span><span style="color: black;">有些</span><span style="color: black;">处理</span><span style="color: black;">方法</span>,<span style="color: black;">没</span>论是“ combo 插件”还是“ flush 插件”,都<span style="color: black;">必须</span><span style="color: black;">咱们</span>修改模块化调用的代码,这<span style="color: black;">没</span>疑是雪上加霜,<span style="color: black;">研发</span>者<span style="color: black;">不仅</span><span style="color: black;">必须</span>在本地<span style="color: black;">研发</span>关注模块化的拆分,在调用的时候还<span style="color: black;">必须</span>关注在一个请求里面加载<span style="color: black;">那些</span>模块比较合适,模块化的初衷是为了<span style="color: black;">加强</span><span style="color: black;">研发</span>效率、降低<span style="color: black;">守护</span>成本,但<span style="color: black;">咱们</span><span style="color: black;">发掘</span><span style="color: black;">这般</span>的模块化<span style="color: black;">方法</span><span style="color: black;">实质</span>上并<span style="color: black;">无</span>降低<span style="color: black;">守护</span>成本,某种程度上<span style="color: black;">来讲</span>使得<span style="color: black;">全部</span>项目更加<span style="color: black;">繁杂</span>了。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">一体化的前端模块化实践<span style="color: black;">方法</span></h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">写到<span style="color: black;">这儿</span>,其实<span style="color: black;">咱们</span>的“前端工程之块化”才正式<span style="color: black;">起始</span>,本文面向对前端模块化<span style="color: black;">研发</span>有所实践或有所<span style="color: black;">科研</span>的<span style="color: black;">朋友</span>,接下来<span style="color: black;">咱们</span>所介绍的前端模块化<span style="color: black;">处理</span><span style="color: black;">方法</span>, 有别于 JavaScript 模块化<span style="color: black;">方法</span>或 CSS 模块化<span style="color: black;">方法</span>,它是一种<span style="color: black;">能够</span>综合处理前端<span style="color: black;">各样</span>资源的模块化<span style="color: black;">方法</span>;它<span style="color: black;">能够</span><span style="color: black;">极重</span><span style="color: black;">提高</span><span style="color: black;">研发</span>者的<span style="color: black;">研发</span>体验,并为性能优化<span style="color: black;">供给</span>良好的支持。下面让<span style="color: black;">咱们</span>来进一步来<span style="color: black;">认识</span>什么是“一体化”的模块化实践<span style="color: black;">方法</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span><span style="color: black;">咱们</span>来看一下一个 web 项目是<span style="color: black;">怎样</span><span style="color: black;">经过</span>“一体化”的模块化<span style="color: black;">方法</span>来划分目录结构:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="http://mmbiz.qpic.cn/mmbiz_png/CpulkszXiaFFFicicKFp9CXHuTXlYFOcsYs6JHwInxYVtmss5vRJ5V5pLXs5XqibB6bHSlU1JXwqPicrOSmVxicfpWicA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">站点(site):<span style="color: black;">通常</span>指能独立<span style="color: black;">供给</span>服务,<span style="color: black;">拥有</span>单独二级域名的<span style="color: black;">制品</span>线。如旅游<span style="color: black;">制品</span>线<span style="color: black;">或</span>特大站点的子站点(lv.baidu.com)。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">子系统(module):<span style="color: black;">拥有</span>较清晰业务<span style="color: black;">规律</span>关系的功能业务集合,<span style="color: black;">通常</span><span style="color: black;">亦</span>叫系统子模块,多个子系统<span style="color: black;">形成</span>一个站点。子系统(module)<span style="color: black;">包含</span>两类: common 子系统, 为其他业务子系统<span style="color: black;">供给</span>规范、资源复用的通用模块;业务子系统:,<span style="color: black;">按照</span>业务、URI 等将站点进行划分的子系统站点。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">页面(page): <span style="color: black;">拥有</span>独立 URL 的输出内容,多个页面<span style="color: black;">通常</span>可<span style="color: black;">构成</span>子系统。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块(widget):能独立<span style="color: black;">供给</span>功能且能够复用的模块化代码,<span style="color: black;">按照</span>复用的方式<span style="color: black;">区别</span>分为 Template 模块、JS 模块、CSS 模块三种类型。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">静态资源(static):非模块化资源目录,<span style="color: black;">包含</span>模板页面引用的静态资源和其他静态资源(favicon,crossdomain.xml 等)。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">前端模块(widget),是能独立<span style="color: black;">供给</span>功能且能够复用的模块化代码,<span style="color: black;">按照</span>复用的方式<span style="color: black;">区别</span>分为 Template 模块、JS 模块、CSS 模块三种类型,CSS 组件,<span style="color: black;">通常</span><span style="color: black;">来讲</span>,CSS 模块是最简单的模块,它只<span style="color: black;">触及</span> CSS 代码与 HTML 代码; JS 模块,稍为<span style="color: black;">繁杂</span>,<span style="color: black;">触及</span> JS 代码,CSS 代码和 HTML 代码。<span style="color: black;">通常</span>,JS 组件<span style="color: black;">能够</span>封装 CSS 组件的代码; Template 模块,<span style="color: black;">触及</span>代码最多,<span style="color: black;">能够</span>综合处理 HTML、JavaScript、CSS 等<span style="color: black;">各样</span>模块化资源,<span style="color: black;">通常</span><span style="color: black;">状况</span>,Template 会将 JS 资源封装成私有 JS 模块、CSS 资源封装成自己的私有 CSS 模块。下面<span style="color: black;">咱们</span>来一一介绍这几种模块的模块化<span style="color: black;">方法</span>。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">模板模块</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">能够</span>将任何一段可复用的模板代码放到一个 smarty 文件中,<span style="color: black;">这般</span>就<span style="color: black;">能够</span>定义一个模板模块。在 widget 目录下的 smarty 模板(本文仅以 Smarty 模板为例)即为模板模块,例如 common 子系统的 widget/nav/ 目录</p>├── nav.css
├── nav.js
└── nav.tpl<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下 nav.tpl 内容如下:</p><span style="color: black;"><nav</span> <span style="color: black;">id=</span><span style="color: black;">"nav"</span> <span style="color: black;">class=</span><span style="color: black;">"navigation"</span> <span style="color: black;">role=</span><span style="color: black;">"navigation"</span><span style="color: black;">></span>
<span style="color: black;"><ul></span>
<span style="color: black;"><</span>%foreach $data as $doc%> <span style="color: black;"><li</span> <span style="color: black;">class=</span><span style="color: black;">"active"</span><span style="color: black;">></span>
<span style="color: black;"><a</span> <span style="color: black;">href=</span><span style="color: black;">"#section-{$doc@index}"</span><span style="color: black;">></span>
<span style="color: black;"><i</span> <span style="color: black;">class=</span><span style="color: black;">"icon-{$doc.icon} icon-white"</span><span style="color: black;">></i><span></span>{$doc.title}<span style="color: black;"></span></span>
<span style="color: black;"></a></span>
<span style="color: black;"></li></span>
<span style="color: black;"><</span>%/foreach%> <span style="color: black;"></ul></span><span style="color: black;"></nav></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">而后</span>,<span style="color: black;">咱们</span>只<span style="color: black;">必须</span>一行代码就<span style="color: black;">能够</span>调用这个<span style="color: black;">包括</span> smarty、JS、CSS 资源的模板模块,</p>// 调用模块的路径为 子系统名<span style="color: black;">叫作</span>:模板在 widget 目录下的路劲
{widget name="common:widget/nav/nav.tpl" }<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这个模板模块(nav)目录下有与模板同名的 JS、CSS 文件,在模板被执行渲染时这些资源会被自动加载。如上所示,定义 template 模块的时候,只需要将 template 所依赖的 JS 模块、CSS 模块存放在同一目录(默认 JavaScript 模块、CSS 模块与 Template 模块同名)下<span style="color: black;">就可</span>,调用者调用 Template 模块只<span style="color: black;">必须</span>写一行代码<span style="color: black;">就可</span>,不<span style="color: black;">必须</span>关注所调用的 template 模块所依赖的静态资源,模板模块会<span style="color: black;">帮忙</span><span style="color: black;">咱们</span>自动处理依赖关系以及资源加载。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">JavaScript 模块</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">上面<span style="color: black;">咱们</span>介绍了一个模板模块是<span style="color: black;">怎样</span>定义、调用以及处理依赖的,接下来<span style="color: black;">咱们</span>来介绍一下模板模块所依赖的 JavaScript 模块是<span style="color: black;">怎样</span>来处理模块交互的。<span style="color: black;">咱们</span><span style="color: black;">能够</span>将任何一段可复用的 JavaScript 代码放到一个 JS 文件中,<span style="color: black;">这般</span>就<span style="color: black;">能够</span>定义为一个 JavaScript 类型的模块,<span style="color: black;">咱们</span><span style="color: black;">没</span>须关心“ define ”闭包的问题,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">得到</span>“ CommonJS ”<span style="color: black;">同样</span>的<span style="color: black;">研发</span>体验,下面是 nav.js 中的源码.</p><span style="color: black;">// common/widget/nav/nav.js</span><span style="color: black;">var</span> <span style="color: black;">$</span> <span style="color: black;">=</span> <span style="color: black;">require</span><span style="color: black;">(</span><span style="color: black;">common:widget/jquery/jquery.js</span><span style="color: black;">);</span><span style="color: black;">exports</span><span style="color: black;">.</span><span style="color: black;">init</span> <span style="color: black;">=</span> <span style="color: black;">function</span><span style="color: black;">()</span> <span style="color: black;">{</span>
<span style="color: black;">...</span><span style="color: black;">};</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span> require、require.async 的方式在任何一个<span style="color: black;">地区</span>(<span style="color: black;">包含</span> html、JavaScript 模块内部)来调用<span style="color: black;">咱们</span><span style="color: black;">必须</span>的 JavaScript 类型模块,require <span style="color: black;">供给</span>的是一种类似于后端语言的同<span style="color: black;">步骤</span>用方式,调用的时候默认所<span style="color: black;">必须</span>的模块都<span style="color: black;">已然</span>加载完成,<span style="color: black;">处理</span><span style="color: black;">方法</span>会负责完成静态资源的加载。require.async <span style="color: black;">供给</span>的是一种异步加载方式,<span style="color: black;">重点</span>用来满足“按需加载”的场景,在 require.async 被执行的时候才去加载所<span style="color: black;">必须</span>的模块,当模块加载回来会执行相应的回调函数,语法如下:</p><span style="color: black;">// 模块名: 文件所在 widget 中路径</span><span style="color: black;">require</span><span style="color: black;">.</span><span style="color: black;">async</span><span style="color: black;">([</span><span style="color: black;">"common:widget/menu/menu.js"</span><span style="color: black;">],</span> <span style="color: black;">function</span><span style="color: black;">(</span> <span style="color: black;">menu</span> <span style="color: black;">)</span> <span style="color: black;">{</span>
<span style="color: black;">menu</span><span style="color: black;">.</span><span style="color: black;">init</span><span style="color: black;">();</span><span style="color: black;">});</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">通常</span> require 用于处理页面首屏所<span style="color: black;">必须</span>的模块,require.async 用于处理首屏外的按需模块。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">CSS 模块</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在模板模块中以及 JS 模块中对应同名的 CSS 模块会自动与模板模块、JS 模块添加依赖关系,进行加载管理,用户不<span style="color: black;">必须</span><span style="color: black;">表示</span>进行调用加载。<span style="color: black;">那样</span><span style="color: black;">怎样</span>在一个 CSS 模块中声明对另一个 CSS 模块的依赖关系呢,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>在注释中的@require 字段标记的依赖关系,这些分析处理对 html 的 style 标签内容<span style="color: black;">一样</span>有效,</p><span style="color: black;">/**
* demo.css
* @require reset.css
*/</span>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">非模块化资源</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在<span style="color: black;">实质</span><span style="color: black;">研发</span>过程中可能存在<span style="color: black;">有些</span>不适合做模块化的静态资源,<span style="color: black;">那样</span><span style="color: black;">咱们</span>依然<span style="color: black;">能够</span><span style="color: black;">经过</span>声明依赖关系来托管给静态资源管理系统来统一管理和加载,</p>{require name="home:static/index/index.css" }<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span><span style="color: black;">经过</span>如上语法<span style="color: black;">能够</span>在页面声明对一个非模块化资源的依赖,在页面运行时<span style="color: black;">能够</span>自动加载<span style="color: black;">关联</span>资源。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">项目实例</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面<span style="color: black;">咱们</span>来看一下在一个<span style="color: black;">实质</span>项目中,<span style="color: black;">倘若</span>在<span style="color: black;">经过</span>页面来调用<span style="color: black;">各样</span>类型的 widget,<span style="color: black;">首要</span>是目录结构:</p>├── common
│ ├── fis-conf.js
│ ├── page
│ ├── plugin
│ ├── static
│ └── widget
└── photo
├── fis-conf.js
├── output
├── page
├── static
├──<span style="color: black;">test</span>
└── widget<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span>有两个子系统,一个 common 子系统(用作通用),一个业务子系统,page 目录用来存放页面,widget 目录用来存放<span style="color: black;">各样</span>类型的模块,static 用于存放非模块化的静态资源,<span style="color: black;">首要</span><span style="color: black;">咱们</span>来看一下 photo/page/index.tpl 页面的源码,</p>{extends file="common/page/layout/layout.tpl"}
{block name="main"}
{require name="photo:static/index/index.css"}
{require name="photo:static/index/index.js"}<span style="color: black;"><h3></span>demo 1<span style="color: black;"></h3></span>
<span style="color: black;"><button</span> <span style="color: black;">id=</span><span style="color: black;">"btn"</span><span style="color: black;">></span>Button<span style="color: black;"></button></span>{script type="text/javascript"}
// 同步调用 jquery
var $ = require(common:widget/jquery/jquery.js);
$(#btn).click(function() {
// 异<span style="color: black;">步骤</span>用 respClick 模块
require.async(, function() {
respClick.hello();
});
});
{/script}
// 调用 renderBox 模块
{widget name="photo:widget/renderBox/renderBox.tpl"}
{/block}<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">第1</span>处代码是对非模块化资源的调用方式;第二处是用 require 的方式调用一个 JavaScript 模块;第三处是<span style="color: black;">经过</span> require.async <span style="color: black;">经过</span>异步的方式来调用一个 JavaScript 模块;最后一处是<span style="color: black;">经过</span> widget 语法来调用一个模板模块。 respclick 模块的源码如下:</p><span style="color: black;">exports</span><span style="color: black;">.</span><span style="color: black;">hello</span> <span style="color: black;">=</span> <span style="color: black;">function</span><span style="color: black;">()</span> <span style="color: black;">{</span>
<span style="color: black;">alert</span><span style="color: black;">(</span><span style="color: black;">hello world</span><span style="color: black;">);</span><span style="color: black;">};</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">renderBox 模板模块的目录结构如下:</p>└── widget
└── renderBox
├── renderBox.css
├── renderBox.js
├── renderBox.tpl
└── shell.jpeg<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">虽然 renderBox 下面<span style="color: black;">包含</span> renderBox.js、renderBox.js、renderBox.tpl 等多种模块,<span style="color: black;">咱们</span>再调用的时候只<span style="color: black;">必须</span>一行代码就<span style="color: black;">能够</span>了,并不<span style="color: black;">必须</span>关注内部的依赖,以及<span style="color: black;">各样</span>模块的初始化问题。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">模块化<span style="color: black;">基本</span>架构</h2>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">总体架构</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">为了实现一种自然、<span style="color: black;">方便</span>、高性能、一体化的模块化<span style="color: black;">方法</span>,<span style="color: black;">咱们</span><span style="color: black;">必须</span><span style="color: black;">处理</span>以下<span style="color: black;">有些</span>问题,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块静态资源管理,<span style="color: black;">通常</span>模块总会<span style="color: black;">包括</span> JavaScript、CSS 等其他静态资源,<span style="color: black;">必须</span>记录与管理这些静态资源</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块依赖关系处理,模块间存在<span style="color: black;">各样</span>依赖关系,在加载模块的时候<span style="color: black;">必须</span>处理好这些依赖关系</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块加载,在模块初始化之前<span style="color: black;">必须</span>将模块的静态资源以及所依赖的模块加载并准备好</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块沙箱(模块闭包),在 JavaScript 模块中<span style="color: black;">咱们</span><span style="color: black;">必须</span>自动对模块添加闭包用于<span style="color: black;">处理</span><span style="color: black;">功效</span>域问题</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">** <span style="color: black;">运用</span>编译<span style="color: black;">工具</span>来管理模块 **</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>编译<span style="color: black;">工具</span>(自动化<span style="color: black;">工具</span>) 对模块进行编译处理,<span style="color: black;">包含</span>对静态资源进行预处理(对 JavaScript 模块添加闭包、对 CSS 进行 LESS 预处理等)、记录<span style="color: black;">每一个</span>静态资源的<span style="color: black;">安排</span>路径以及依赖关系并生成资源表(resource map)。<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>编译<span style="color: black;">工具</span>来托管所有的静态资源,<span style="color: black;">这般</span><span style="color: black;">能够</span>帮<span style="color: black;">咱们</span><span style="color: black;">处理</span>模块静态资源管理、模块依赖关系、模块沙箱问题。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">** <span style="color: black;">运用</span>静态资源加载框架来加载模块 **</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">那样</span><span style="color: black;">怎样</span><span style="color: black;">处理</span>模块加载问题,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>静态资源加载框架来<span style="color: black;">处理</span>,<span style="color: black;">重点</span><span style="color: black;">包括</span>前端模块加载框架,用于 JavaScript 模块化支持,<span style="color: black;">掌控</span>资源的异步加载。后端模块化框架,用于<span style="color: black;">处理</span> JavaScript 同步加载、CSS 和模板等模块资源的加载,静态资源加载框架<span style="color: black;">能够</span>用于对页面进行<span style="color: black;">连续</span>的自适应的前端性能优化,自动对页面的<span style="color: black;">区别</span><span style="color: black;">状况</span>投递<span style="color: black;">区别</span>的资源加载<span style="color: black;">方法</span>,<span style="color: black;">帮忙</span><span style="color: black;">研发</span>者管理静态资源,抹平本地<span style="color: black;">研发</span>到<span style="color: black;">安排</span>上线的性能沟壑。 编译<span style="color: black;">工具</span>和静态资源加载框架的流程图如下:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="http://mmbiz.qpic.cn/mmbiz_jpg/CpulkszXiaFFFicicKFp9CXHuTXlYFOcsYsoz8JDLac1ARDXO8ibLV18PrtVANVxOWVygBibrED2tcGsNJAOibIibibBfQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">编译<span style="color: black;">工具</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">自动化<span style="color: black;">工具</span>会扫描目录下的模块进行编译处理并输出产出文件:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">静态资源</strong>,经过编译处理过的 JavaScript、CSS、Image 等文件,<span style="color: black;">安排</span>在 CDN 服务器自动添加闭包,<span style="color: black;">咱们</span><span style="color: black;">期盼</span>工程师在<span style="color: black;">研发</span> JavaScript 模块的时候不<span style="color: black;">必须</span>关心” define ”闭包的事情,<span style="color: black;">因此</span>采用<span style="color: black;">工具</span>自动帮工程师添加闭包支持,例如如上定义的 nav.js 模块在经过自动化<span style="color: black;">工具</span>处理后变成如下,</p><span style="color: black;">define</span><span style="color: black;">(</span><span style="color: black;">common:widget/nav/nav.js</span><span style="color: black;">,</span> <span style="color: black;">function</span><span style="color: black;">(</span> <span style="color: black;">require</span><span style="color: black;">,</span> <span style="color: black;">exports</span><span style="color: black;">,</span> <span style="color: black;">module</span> <span style="color: black;">)</span> <span style="color: black;">{</span>
<span style="color: black;">// common/widget/nav/nav.js</span>
<span style="color: black;">var</span> <span style="color: black;">$</span> <span style="color: black;">=</span> <span style="color: black;">require</span><span style="color: black;">(</span><span style="color: black;">common:widget/jquery/jquery.js</span><span style="color: black;">);</span>
<span style="color: black;">exports</span><span style="color: black;">.</span><span style="color: black;">init</span> <span style="color: black;">=</span> <span style="color: black;">function</span><span style="color: black;">()</span> <span style="color: black;">{</span>
<span style="color: black;">...</span>
<span style="color: black;">};</span><span style="color: black;">});</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">模板文件</strong>,经过编译处理过的 smarty 文件,自动<span style="color: black;">安排</span>在模板服务器</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">资源表</strong>,记录<span style="color: black;">每一个</span>静态资源的<span style="color: black;">安排</span>路径以及依赖关系,用于静态资源加载框架 静态资源加载框架(SR Management System)会加载 source maps 拿到页面所<span style="color: black;">必须</span>的所有模块以及静态资源的 url,<span style="color: black;">而后</span>组织资源输出<span style="color: black;">最后</span>页面。</p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;">静态资源加载框架</h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">下面<span style="color: black;">咱们</span>会<span style="color: black;">仔细</span>讲解<span style="color: black;">怎样</span>加载模块,如下所示,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="http://mmbiz.qpic.cn/mmbiz_jpg/CpulkszXiaFFFicicKFp9CXHuTXlYFOcsYsIXD9Izr4O2qKvz1cgMeOSNCBJ5mrWxOGsNVKzo6dODb4IoHY7coUYw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在流程<span style="color: black;">起始</span>前<span style="color: black;">咱们</span><span style="color: black;">必须</span>准备两个数据结构:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">uris = [],数组,<span style="color: black;">次序</span>存放要输出资源的 uri</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">has = {},hash 表,存放已收集的静态资源,防止重复加载</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">加载资源表(resource map):</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">javascript { "res": { "A/A.tpl": { "uri": "/templates/A.tpl", "deps": ["A/A.css"] }, "A/A.css": { "uri": "/static/css/A_7defa41.css" }, "B/B.tpl": { "uri": "/templates/B.tpl", "deps": ["B/B.css"] }, "B/B.css": { "uri": "/static/css/B_33c5143.css" }, "C/C.tpl": { "uri": "/templates/C.tpl", "deps": ["C/C.css"] }, "C/C.css": { "uri": "/static/css/C_6a59c31.css" } } }</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">执行 {widget name=”A”}</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">```javascript urls = [ ‘/static/css/A_7defa41.css’ ];</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">has = { “A/A.css”: true } ```</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在表中<span style="color: black;">查询</span> id 为 A/A.tpl 的资源,取得它的资源路径 /template/A.tpl,记为 tpl_path,加载并渲染 tpl_path 所指向的模板文件,即 /template/A.tpl,并输出它的 html 内容</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">查看 A/A.tpl 资源的 deps 属性,<span style="color: black;">发掘</span>它依赖资源 A/A.css,在表中<span style="color: black;">查询</span> id 为 A/A.css 的资源,取得它的资源路径为 /static/css/A7defa41.css_,存入 uris 数组 中,并在 has 表 里标记已加载 A/A.css 资源,<span style="color: black;">咱们</span>得到:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">依次执行 {widget name=”B”}、{widget name=”c”},<span style="color: black;">过程</span>与<span style="color: black;">以上</span><span style="color: black;">过程</span> 3 相同,得到,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">```javascript urls = [ ‘/static/css/A_7defa41.css’, ‘/static/css/B_33c5143.css’, ‘/static/css/C_6a59c31.css’ ];</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">has = { “A/A.css”: true, “B/B.css”: true, “C/C.css”: true }</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">```</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在要输出的 html 前面,<span style="color: black;">咱们</span>读取 uris 数组的数据,生成静态资源外链,<span style="color: black;">咱们</span>得到<span style="color: black;">最后</span>的 html 结果:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">```html</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">html of A</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">html of B</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">html of C</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">``` 上面讲的是对模板和 CSS 资源的加载,用于描述静态资源加载的流程,下面<span style="color: black;">咱们</span>再来<span style="color: black;">仔细</span>讲解下<span style="color: black;">针对</span> JavaScript 模块的处理,<span style="color: black;">想要</span>在前端实现类似“ commonJS ”<span style="color: black;">同样</span>的模块化<span style="color: black;">研发</span>体验<span style="color: black;">必须</span>前端模块化框架和后端模块化框架<span style="color: black;">一块</span><span style="color: black;">功效</span>来实现,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">前端模块化框架</strong>,原理上<span style="color: black;">大众</span><span style="color: black;">能够</span><span style="color: black;">选取</span><span style="color: black;">运用</span> requireJS 或 SeaJS 来<span style="color: black;">做为</span>模块化支持,<span style="color: black;">然则</span><span style="color: black;">咱们</span>并不<span style="color: black;">意见</span>这么做,<span style="color: black;">咱们</span><span style="color: black;">意见</span><span style="color: black;">大众</span><span style="color: black;">运用</span>一个 mininal AMD API,例如 requireJS 的 almond 版本<span style="color: black;">或</span>其他的精简版本,requireJS 完整版有 2000 余行,而精简版模块化框架只<span style="color: black;">必须</span> 100 行代码<span style="color: black;">上下</span>就<span style="color: black;">能够</span>实现,只<span style="color: black;">必须</span>实现以下功能:</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块定义,只<span style="color: black;">必须</span>实现如下接口 define (id, factory),<span style="color: black;">由于</span> define 闭包是<span style="color: black;">工具</span>生成,<span style="color: black;">因此</span><span style="color: black;">咱们</span>不<span style="color: black;">必须</span><span style="color: black;">思虑</span>匿名闭包的实现,<span style="color: black;">同期</span><span style="color: black;">亦</span>不<span style="color: black;">必须</span><span style="color: black;">思虑</span>“依赖前置”的支持,<span style="color: black;">咱们</span>只<span style="color: black;">必须</span>支持一种最简单直接的模块化定义<span style="color: black;">就可</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块同<span style="color: black;">步骤</span>用,require (id),静态资源管理系统会<span style="color: black;">保准</span>所需的模块都已预先加载,<span style="color: black;">因此呢</span> require <span style="color: black;">能够</span>立即返回该模块</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块异<span style="color: black;">步骤</span>用,<span style="color: black;">思虑</span>到有些模块<span style="color: black;">没</span>需再<span style="color: black;">起步</span>时载入,<span style="color: black;">因此呢</span><span style="color: black;">咱们</span><span style="color: black;">必须</span><span style="color: black;">供给</span>一个<span style="color: black;">能够</span>在运行时加载模块的接口 require.async (names, callback),names <span style="color: black;">能够</span>是一个 id,<span style="color: black;">或</span>是数组形式的 id 列表。当所有都加载都完成时,callback 被调用,names 对应的模块实例将依次传入。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">模块自执行,即 AMD 规范的提前执行,之所<span style="color: black;">选取</span><span style="color: black;">这般</span>做的<span style="color: black;">原由</span>是<span style="color: black;">思虑</span>到 Template 模块的特殊性,<span style="color: black;">通常</span> Template 模块都会依赖 JavaScript 模块来做初始化工作,<span style="color: black;">选取</span>模块自执行的方式<span style="color: black;">咱们</span>就不<span style="color: black;">必须</span>显式的在 Template 页面上书写 require 依赖,静态资源系统会自动加载 Template 模块的依赖,当模块并行加载结束后会一次自执行。<span style="color: black;">大众</span>可能会认为如果页面存在<span style="color: black;">有些</span>用不到的模块那都自执行岂不会浪费资源,<span style="color: black;">这儿</span><span style="color: black;">大众</span><span style="color: black;">能够</span><span style="color: black;">不消</span>担心,静态资源系统投放到前端的模块都是页面初始化所<span style="color: black;">必须</span>的,不存在浪费资源的<span style="color: black;">状况</span>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Resource map 前端支持,<span style="color: black;">重点</span>用于为异步模块调用<span style="color: black;">供给</span> uri 支持,resourceMap 为静态资源管理系统自动生成,<span style="color: black;">没</span>需人工调用,用于<span style="color: black;">查找</span>一个异步模块的真正 url,用于自动处理异步模块的 CDN、资源打包合并、强缓存问题,格式如下,</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">javascript require.resourceMap({ "res": { "common:widget/sidebar/sidebar.async.js": { "url": "/static/common/widget/sidebar/sidebar.async_449e169.js" } } });</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">处理循环引用,参照 nodeJS 处理循环引用的方式,在<span style="color: black;">导致</span>循环依赖的 require 之前把<span style="color: black;">必须</span>的东西 exports 出去,例如</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">```javascript // a.js console.log(‘a string’); exports.done = false; var b = require(‘./b.js’); console.log(‘in a, b.done = ‘ + b.done); exorts.done = true; console.log(‘b done’);</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">// b.js console.log(‘b starting’); exports.done = false;</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">var a = require(‘./a.js’); console.log(‘in b, a.done = ‘ + a.done); exports.done = true; console.log(‘b done’);</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">// main.js console.log(‘main starting’); var a = require(‘./a.js’); var b = require(‘./b.js’); console.log(‘in main. a.done = ‘ + a.done + ‘, b.done = ‘ + b.done); ```</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">倘若</span>在加载 a 的过程中,有其他的代码(假设为 b)require a.js 的话,<span style="color: black;">那样</span> b <span style="color: black;">能够</span>从 cache 中直接取到 a 的 module,从而不会<span style="color: black;">导致</span>重复加载的死循环。但带来的代价<span style="color: black;">便是</span>在 load 过程中,b 看到的是不完整的 a。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">后端模块加载框架,<span style="color: black;">重点</span>用于处理模块的依赖并生成模块静态资源外链,下面<span style="color: black;">咱们</span>将以实例讲解静态资源管理系统是<span style="color: black;">怎样</span>对 JavaScript 模块进行加载的,如下<span style="color: black;">咱们</span>有一个 sidebar 模块,目录下有如下资源</p>├── sidebar.async.js
├── sidebar.css
├── sidebar.js
└── sidebar.tpl<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">sidebar.tpl 中的内容如下,</p><span style="color: black;"><a</span> <span style="color: black;">id=</span><span style="color: black;">"btn-navbar"</span> <span style="color: black;">class=</span><span style="color: black;">"btn-navbar"</span><span style="color: black;">></span>
<span style="color: black;"><span</span> <span style="color: black;">class=</span><span style="color: black;">"icon-bar"</span><span style="color: black;">></span></span>
<span style="color: black;"><span</span> <span style="color: black;">class=</span><span style="color: black;">"icon-bar"</span><span style="color: black;">></span></span>
<span style="color: black;"><span</span> <span style="color: black;">class=</span><span style="color: black;">"icon-bar"</span><span style="color: black;">></span></span><span style="color: black;"></a></span>{script}
$(a.btn-navbar).click(function() {
require.async(./sidebar.async.js, function( sidebar ) {
sidebar.run();
});
});
{/script}<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">对项目编译后,自动化<span style="color: black;">工具</span>会分析模块的依赖关系,并生成 map.json,如下</p><span style="color: black;">"common:widget/sidebar/sidebar.tpl"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"common/widget/sidebsr/sidebar.tpl"</span><span style="color: black;">,</span>
<span style="color: black;">"type"</span><span style="color: black;">:</span> <span style="color: black;">"tpl"</span><span style="color: black;">,</span>
<span style="color: black;">"extras"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"async"</span><span style="color: black;">:</span> <span style="color: black;">[</span>
<span style="color: black;">"common:widget/sidebar/sidebar.async.js"</span>
<span style="color: black;">]</span>
<span style="color: black;">},</span>
<span style="color: black;">"deps"</span><span style="color: black;">:</span> <span style="color: black;">[</span>
<span style="color: black;">"common:widget/sidebar/sidebar.js"</span><span style="color: black;">,</span>
<span style="color: black;">"common:widget/sidebar/sidebar.css"</span>
<span style="color: black;">]</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">在 sidebar 模块被调用后,静态资源管理系统<span style="color: black;">经过</span><span style="color: black;">查找</span> map.json <span style="color: black;">能够</span>得知,当前 sidebar 模块同步依赖 sidebar.js、sidebar.css,异步依赖 sdebar.async.js,在要输出的 html 前面,<span style="color: black;">咱们</span>读取 uris 数组的数据,生成静态资源外链,<span style="color: black;">咱们</span>得到<span style="color: black;">最后</span>的 html</p><span style="color: black;"><script </span><span style="color: black;">type=</span><span style="color: black;">"text/javascript"</span><span style="color: black;">></span>
<span style="color: black;">require</span><span style="color: black;">.</span><span style="color: black;">resourceMap</span><span style="color: black;">({</span>
<span style="color: black;">"res"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"common:widget/sidebar/sidebar.async.js"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"url"</span><span style="color: black;">:</span> <span style="color: black;">"/satic/common/widget/sidebar/sidebar.async_449e169.js"</span>
<span style="color: black;">}</span>
<span style="color: black;">}</span>
<span style="color: black;">});</span><span style="color: black;"></script></span><span style="color: black;"><script </span><span style="color: black;">type=</span><span style="color: black;">"text/javascript"</span> <span style="color: black;">src=</span><span style="color: black;">"/static/common/widget/sidebar/sidebar_$12cd4.js"</span><span style="color: black;">></script></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">如上可见,后端模块化框架将同步模块的 script url 统<span style="color: black;">一辈子</span>成到页面底部,将 css url 统<span style="color: black;">一辈子</span>成在 head 中,<span style="color: black;">针对</span>异步模块(require.async)注册 resourceMap 代码,框架会<span style="color: black;">经过</span>{script}标签收集到页面所有 script,统一管理并按<span style="color: black;">次序</span>输出 script 到相应位置。</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">自适应的性能优化</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">此刻</span>,当<span style="color: black;">咱们</span>想对模块进行打包,该<span style="color: black;">怎样</span>处理呢,<span style="color: black;">咱们</span><span style="color: black;">首要</span><span style="color: black;">运用</span>一个 pack 配置项(下面是 fis 的打包配置项),对网站的静态资源进行打包,配置文件大致为,</p><span style="color: black;">fis</span><span style="color: black;">.</span><span style="color: black;">config</span><span style="color: black;">.</span><span style="color: black;">merge</span><span style="color: black;">({</span>
<span style="color: black;">pack</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">p<span style="color: black;">公斤</span>/aio.css</span><span style="color: black;">:</span> <span style="color: black;">**.css</span>
<span style="color: black;">}</span><span style="color: black;">});</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span>编译项目看一下产出的 map.json(resource map),有何变化,</p><span style="color: black;">{</span>
<span style="color: black;">"res"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"A/A.tpl"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/template/A.tpl"</span><span style="color: black;">,</span>
<span style="color: black;">"deps"</span><span style="color: black;">:</span> <span style="color: black;">[</span><span style="color: black;">"A/A.css"</span><span style="color: black;">]</span>
<span style="color: black;">},</span>
<span style="color: black;">"A/A.css"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/static/csss/A_7defa41.css"</span><span style="color: black;">,</span>
<span style="color: black;">"p<span style="color: black;">公斤</span>"</span><span style="color: black;">:</span> <span style="color: black;">"p0"</span>
<span style="color: black;">},</span>
<span style="color: black;">"B/B.tpl"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/template/B.tpl"</span><span style="color: black;">,</span>
<span style="color: black;">"deps"</span><span style="color: black;">:</span> <span style="color: black;">[</span><span style="color: black;">"B/B.css"</span><span style="color: black;">]</span>
<span style="color: black;">},</span>
<span style="color: black;">"B/B.css"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/static/csss/B_33c5143.css"</span><span style="color: black;">,</span>
<span style="color: black;">"p<span style="color: black;">公斤</span>"</span><span style="color: black;">:</span> <span style="color: black;">"p0"</span>
<span style="color: black;">},</span>
<span style="color: black;">"C/C.tpl"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/template/C.tpl"</span><span style="color: black;">,</span>
<span style="color: black;">"deps"</span><span style="color: black;">:</span> <span style="color: black;">[</span><span style="color: black;">"C/C.css"</span><span style="color: black;">]</span>
<span style="color: black;">},</span>
<span style="color: black;">"C/C.css"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/static/csss/C_ba59c31.css"</span><span style="color: black;">,</span>
<span style="color: black;">"p<span style="color: black;">公斤</span>"</span><span style="color: black;">:</span> <span style="color: black;">"p0"</span>
<span style="color: black;">},</span>
<span style="color: black;">},</span>
<span style="color: black;">"p<span style="color: black;">公斤</span>"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"p0"</span><span style="color: black;">:</span> <span style="color: black;">{</span>
<span style="color: black;">"uri"</span><span style="color: black;">:</span> <span style="color: black;">"/static/p<span style="color: black;">公斤</span>/aio_0cb4a19.css"</span><span style="color: black;">,</span>
<span style="color: black;">"has"</span><span style="color: black;">:</span> <span style="color: black;">[</span><span style="color: black;">"A/A.css"</span><span style="color: black;">,</span> <span style="color: black;">"B/B.css"</span><span style="color: black;">,</span> <span style="color: black;">"C/C.css"</span><span style="color: black;">]</span>
<span style="color: black;">}</span>
<span style="color: black;">}</span><span style="color: black;">}</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">大众</span><span style="color: black;">重视</span>到了么,表里多了一张 p<span style="color: black;">公斤</span> 表,所有被打包的资源会有一个 p<span style="color: black;">公斤</span> 属性 指向该表中的资源,而这个资源,正是<span style="color: black;">咱们</span>配置的打包策略。<span style="color: black;">这般</span>静态资源管理系统在表中<span style="color: black;">查询</span> id 为 A/A.css 的资源,<span style="color: black;">咱们</span><span style="color: black;">发掘</span>该资源有 p<span style="color: black;">公斤</span> 属性,<span style="color: black;">显示</span>它被备份在了一个打包文件中。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">运用</span>它的 p<span style="color: black;">公斤</span> 属性值 p0 <span style="color: black;">做为</span> key,在 p<span style="color: black;">公斤</span> 表里读取信息,取的这个包的资源路径为 /static/p<span style="color: black;">公斤</span>/aio0cb4a19.css_ 存入 uris 数组 中将 p0 包的 has 属性所声明的资源加入到 has 表,在要输出的 html 前面,<span style="color: black;">咱们</span>读取 uris 数组 的数据,生成静态资源外链,<span style="color: black;">咱们</span>得到<span style="color: black;">最后</span>的 html 结果:</p><span style="color: black;"><html></span>
<span style="color: black;"><link</span> <span style="color: black;">href=</span><span style="color: black;">"/static/p<span style="color: black;">公斤</span>/aio_0cb4a19.css"</span><span style="color: black;">></span>
<span style="color: black;"><div></span>html of A<span style="color: black;"></div></span>
<span style="color: black;"><div></span>html of B<span style="color: black;"></div></span>
<span style="color: black;"><div></span>html of C<span style="color: black;"></div></span><span style="color: black;"></html></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">静态资源管理系统<span style="color: black;">能够</span><span style="color: black;">非常</span>灵活的适应<span style="color: black;">各样</span>性能优化场景,<span style="color: black;">咱们</span>还<span style="color: black;">能够</span>统计 {widget} 插件的调用<span style="color: black;">状况</span>,<span style="color: black;">而后</span>自动生成最优的打包配置,让网站<span style="color: black;">能够</span>自适应优化,<span style="color: black;">这般</span>工程师<span style="color: black;">不消</span>关心资源在哪,怎么来的,怎么没的,所有资源定位的事情,都交给静态资源管理系统就好了。静态资源路径都带 md5 戳,这个值只跟内容有关,静态资源服务器从此<span style="color: black;">能够</span><span style="color: black;">安心</span>开启强缓存了!还能实现静态资源的分级发布,<span style="color: black;">容易</span>回滚!<span style="color: black;">咱们</span>还<span style="color: black;">能够</span>继续<span style="color: black;">科研</span>,<span style="color: black;">例如</span><span style="color: black;">按照</span>国际化、皮肤,终端等信息约定一种资源路径规范,当后端适配到特定地区、特定机型的<span style="color: black;">拜访</span>时,静态资源管理系统帮你送达<span style="color: black;">区别</span>的资源给<span style="color: black;">区别</span>的用户。说到<span style="color: black;">这儿</span>,<span style="color: black;">大众</span>应该比较清楚<span style="color: black;">全部</span>“一体化”的模块化<span style="color: black;">处理</span><span style="color: black;">方法</span>了,有人可能会问,<span style="color: black;">这般</span>做岂不是<span style="color: black;">增多</span>了后端性能开销?<span style="color: black;">针对</span>这个问题,<span style="color: black;">咱们</span>实践过的经验是,这非常值得!其实这个后端开销很少,算法非常简单直白,但他所换来的前端工程化水平<span style="color: black;">加强</span>非常大!</p>
<h2 style="color: black; text-align: left; margin-bottom: 10px;">总结</h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本文是 fis 前端工程系列<span style="color: black;">文案</span>中的一部分,其实在前端<span style="color: black;">研发</span>工程管理<span style="color: black;">行业</span>还有<span style="color: black;">非常多</span>细节值得探索和挖掘,<span style="color: black;">提高</span>前端团队生产力水平并不是一句空话,它<span style="color: black;">必须</span><span style="color: black;">咱们</span>能对前端<span style="color: black;">研发</span>及代码运行有更深刻的认识,对性能优化原则有更细致的分析与<span style="color: black;">科研</span>。fis 团队<span style="color: black;">始终</span>致力于从架构而非经验的<span style="color: black;">方向</span>实现性能优化原则,<span style="color: black;">处理</span>前端工程师<span style="color: black;">研发</span>、调试、<span style="color: black;">安排</span>中遇到的工程问题,<span style="color: black;">供给</span>组件化框架,<span style="color: black;">加强</span>代码复用率,<span style="color: black;">供给</span><span style="color: black;">研发</span><span style="color: black;">工具</span>集,<span style="color: black;">提高</span>工程师的<span style="color: black;">研发</span>效率。在前端工业化<span style="color: black;">研发</span>的所有环节均有可节省的人力成本,这些成本非常可观,相信<span style="color: black;">此刻</span><span style="color: black;">非常多</span>大型互联网<span style="color: black;">机构</span><span style="color: black;">亦</span>都有了<span style="color: black;">这般</span>的共识。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本文只是将这个<span style="color: black;">行业</span>中很小的一部分知识的展开讨论,抛砖引玉,<span style="color: black;">期盼</span>能为业界<span style="color: black;">关联</span><span style="color: black;">行业</span>的工作者<span style="color: black;">供给</span><span style="color: black;">有些</span>不<span style="color: black;">同样</span>的思路。欢迎关注fis项目,对本文有任何意见或<span style="color: black;">意见</span>都<span style="color: black;">能够</span>在fis开源项目中进行反馈和讨论。</p>
楼主的文章非常有意义,提升了我的知识水平。 楼主节操掉了,还不快捡起来! 期待更新、坐等、迫不及待等。 谷歌外贸网站优化技术。
页:
[1]