lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
624 stars 35 forks source link

将组件合并成一个文件 #7

Open lmk123 opened 9 years ago

lmk123 commented 9 years ago

先来说说我对“组件”的定义。

前端开发过程中,可能会用到一些第三方插件,比如 jBox 或者 asDatepicker:这些插件会附带一个 css 文件用来定义样式。于是我们在使用这些插件的时候,页面看上去是这样的:

<link rel="stylesheet" href="jBox.css">
<script src="jBox.js"></script>

这里有一个小问题:既然需要加载 jBox.js 的时候总是需要加载 jBox.css 的,那为什么不将 jBox.css 写进 jBox.js 呢?这样可以减少一次 HTTP 请求。

但是总所周知,在 js 里的长文本是很难维护的,所以最好的解决方案是:开发时分成多个文件,但在生产环境时合并成一个文件;相关的文件最好放在一处,比如说放在同一个文件夹下——这就是我所认为的“组件”的定义。

require.js 配合 text插件r.js 文件组合工具就可以实现上面的需求了,只是 r.js 的配置有点繁琐:它是奔着将所有的依赖文件都合并在一起的目标去的,而我这里的需求是只想合并组件而已,为此我不得不为每一个组件进行单独配置,这肯定是不利于维护的。

于是,我自己动手写了一个小工具:requirejs-components-combine,它的作用单一而简单,但可以很好的满足我的需求。

举个例子。我有一个组件叫 modal-box,这个组件的作用是取代浏览器的 alert()confirm() 方法,它的文件结构如下:

modal-box/
    |----- template.html(模板)
    |----- modal.css(样式)
    ------ index.js (逻辑)

下面简单列出这三个文件的内容: template.html

<!-- 前略 -->
<body>
    <div class="modal-box">Hello World</div>
</body></html>

modal.css

.modal-box { color:red; display:none }

index.js

define(['jquery', 'text!template.html!strip', 'text!modal.css'], function ($, HTML, CSS) {
     var $modal = $( HTML ).appendTo( 'body' );
    $('<style>' + CSS + '</style>').appendTo( 'head' );
    return {
        show: function () { $modal.show(); } ,
        hide: function () { $midal.hide(); }
    };
} );

最后,我们在代码里应该是这样使用它的: test.js

require( ['modal-box/index'] , function (modal) {
    modal.show();
});

这样,开发时避免了将模板与样式直接写进 index.js 里,而在上线前,就可以使用我的小工具进行合并了,合并之后的文件结构是这样的:

modal-box/
    |----- template.html(模板)
    |----- modal.css(样式)
    ------ index.js (逻辑)
modal-box.js(合并后的文件)

modal-box.js 的内容是:

define('_template.html',function(){return'<div class="modal-box">Hello World</div>'});
define('_modal.css',function(){return'.modal-box { color:red; display:none }'});
define( [ 'jquery' , '_template.html' , '_modal.css' ] , function (  $ , HTML , CSS ) {
     var $modal = $( HTML ).appendTo( 'body' );
    $('<style>' + CSS + '</style>').appendTo( 'head' );
    return {
        show:function () { $modal.show(); } ,
        hide:function () { $midal.hide(); }
    };
} );

最后,我们还需要将 test.js 里面的引用从 modal-box/index 改成 modal-box;我们可以在开发时就写一个“代理模块”,避免每次组合完成后都需要更改模块引用: 开发时就先写一个 modal-box.js

define(['modal-box/index'],function (m) { return m; });

组件合并工具会覆盖这个“代理模块”,那么在开发时,test.js就可以放心的引用 modal-box ,不需要更改模块引用了。

就是这样了!

mrbenlearnjs commented 9 years ago

hi,可以请教个问题么,最近在做一个chrome-app遇到些问题,这个app想实现的功能是改变hosts,node程序写好了,但是我app怎么调用node程序呢,就是html上的事件怎么调用node指令 ,你知道nodejs操作fs的时候都是类似node test.js arguments的形式,或者是方在grunt里面执行的,不知道html上的事件怎么和这些联系起来~

lmk123 commented 9 years ago

@mrbenlearnjs 如果你是想知道怎么用 nodejs 搭建一个 web 服务器,那看看它内置的 HTTP 模块就知道了,不过大部分人都使用 Express 来完成这个功能。

如果你是想在 chrome-app 里面调用 nodejs 命令行来修改用户的 hosts 文件,那么就我所知,这是做不到的(即使做得到,这也需要用户先把你的 nodejs 程序下载到本地)。你应该尝试使用 FileSystem API

mrbenlearnjs commented 9 years ago

3q~你是做后端的吗 感觉你懂很多 之前没看到chrome也有fs 就想用node做

mrbenlearnjs commented 9 years ago

你说chrome-app里面不好调用nodejs指令 但是看的项目里面有不少node的东西 nodejs是怎么和app联系起来的

lmk123 commented 9 years ago

@mrbenlearnjs 以我的 书虫 项目为例,其中 Chrome 扩展属于客户端,而 nodejs (或者说是用 nodejs 搭建起来的 web 服务器)是服务端,它们两个只是放在了同一个文件夹里,实际上是两个不同的执行环境,通过 HTTP 协议(或者说 AJAX) 交换数据。

当你把 nodejs 程序下载到自己电脑后,你自己的电脑就成了“服务端”,所以你可以用 nodejs 改你自己电脑上的文件啥的;但是对于使用你的 Chrome App 的用户来说,总不可能在商店里下载了你的 Chrome App 之后,你还让他去把你的 nodejs 程序也下载并安装(还得运行)到他的电脑上去吧?

mrbenlearnjs commented 9 years ago

有道理!