惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
www.infosecurity-magazine.com
www.infosecurity-magazine.com
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - Franky
人人都是产品经理
人人都是产品经理
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Cloudflare Blog
N
News and Events Feed by Topic
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
AWS News Blog
AWS News Blog
S
SegmentFault 最新的问题
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Spread Privacy
Spread Privacy
J
Java Code Geeks
博客园 - 聂微东
T
Tor Project blog
宝玉的分享
宝玉的分享
博客园 - 叶小钗
Webroot Blog
Webroot Blog
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
H
Heimdal Security Blog
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
I
InfoQ
Security Latest
Security Latest
Martin Fowler
Martin Fowler
Hacker News: Ask HN
Hacker News: Ask HN
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
Latest news
Latest news
雷峰网
雷峰网
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cisco Blogs
H
Help Net Security
L
LINUX DO - 最新话题
L
LINUX DO - 热门话题

囧克斯

奔四了,写给40岁的自己 有序退网 我和 Vue.js 的十年 我参与《代码之外 Beyond Code》的故事 博客站迁移至 VitePress 的备忘 写给我的奶奶 中文格式化小工具 zhlint 及其开发心得 vue-mark-display:用 markdown 语法轻松撰写幻灯片 我对技术会议的一些看法 VueConf Hangzhou 见闻 第四届 CSSConf CN 见闻 [译]Web 表单的未来 [译]苹果正在做一些他们的程序员明摆着不想要的东西 [译]为什么我不会无偿加班且你也不应该 [译]如果管理是唯一可走的路,那就完蛋了 [译]如何撰写 Git 提交信息 [译]C 程序的原则 Vue 2.0 来了! Weex 近 4 个月的开源之路 Weex 在 JS Runtime 内的多实例管理 我理解的 SPA 我理解的 Flux 架构 【整理】Vue 2.0 自 beta 1 到 beta 4 以来的主要更新 通过一张图走进 Vue 2.0 Code Review for Vue 2.0 Preview Vue 2.0 发布啦! 务实的小而美 Vue.js 1.0.0 发布了! [译]如何成为一名卓越的前端工程师 手机淘宝前端的图片相关工作流程梳理 [译]如何让办公室政治最小化 Vue.js 源码学习笔记 从原型到发布——“团队时间线” 1.0 开发心得 Vue + webpack 项目实践 用 Koa 写服务体验 webcomponents 笔记 之 配置管理 小秀个人的13~14年摄影作品 (共19张) 由今年D2前端论坛想到的 [译]CSS命名神马的真心难 [译]Git 分支的最佳实践 [译]撰写可测试的 JavaScript [译]语义化版本管理 [译]通过HTML5 Canvas API调节图像的亮度和颜色 [译]JavaScript V8性能小贴士 [译]视觉差,走起! [译]Chrome开发者工具中评估性能的五大新特性 精气神儿 细节无微不至,彩屏让人又爱又恨——新老“神机”大对决:Nokia 1050 vs Nokia 1202 秦升拿到红牌之后…… 用Sass重新整理自己的博客主题样式 Connect中间件使用手册 编辑器小调查结果 [译]JSLint 文档 烟火——写给蛇年的傲游和我 小秀个人的全年摄影作品 (共15张) 2012年终毫无正能量的总结 标签?ID?还是CLASS? 微创新=伪创新 HTML5峰会归来 分享bookmarklet一则:随意阅读 国际羽联和中国队之间的恶性循环 ZeroClipboard 学习笔记 “思考人生” 听杨东杰弹吉他 学习精髓 网站装修笔记20120426 网站装修笔记20120414 网站装修笔记20120406 分享Typecho插件:百度统计助手 我的得奖感言 网站装修笔记20120331 用CSS3制作尖角标签按钮样式 分享Typecho插件:Markdown 解析器 + 编辑器 分享Typecho皮肤:我的字很大 汇总自己过去的一些HTML5科普文章 html5中的消息通信简介 + 我的新网站开张 网站装修计划 Typed Arrays 是神马? 文明看球 HTML5中的文件处理 之 File Writer API HTML5中的文件处理 之 File API 独生子女、互相等和不耐烦 IndexedDB技术简介(四) IndexedDB技术简介(三) IndexedDB技术简介(二) IndexedDB技术简介(一) 把博客的字体进一步调大,同时去掉了侧边栏 “模仿别人是为了找到自己” 写给我未婚妻的2011年 写给自己的2011年 手把手教你入门EaselJS做HTML5动画 “吃了吧,不吃就浪费了” 写给傲游的2011年 所谓专业 写给HTML5的2011年 对HTML5中LocalStorage的一些使用建议 回味一下我2011年看到的最过瘾的5场足球比赛 浅浅浅谈开饭店被顾客吃出“异物”的用户体验 前端的本职 继续对Mac穷追猛打 之 修改原生按钮文字大小的技巧
巧用 RequireJS Optimizer 给传统的前端项目打包
勾三股四 · 2013-03-30 · via 囧克斯

r.js 本是 RequireJS 的一个附属产品,支持在 NodeJS、Rhino 等环境下运行 AMD 程序,并且其包含了一个名为 RequireJS Optimizer 的工具,可以为项目完成合并脚本等优化操作。

r.js 的介绍中明确写道它是 RequireJS 项目的一部分,和 RequireJS 协同工作。但我发现,RequireJS Optimizer 提供了丰富的配置参数,可以让我们完全跳出 AMD 和 RequireJS 程序的束缚,为我们的前端程序服务。


RequireJS Optimizer 常规用法 ​

首先,简单介绍一下 RequireJS Optimizer 的“正派”用法 (以 NodeJS 环境为例):

事先写好一个配置文件,比如 config.js,它是 JSON 格式的,常用属性有:

{
    // 程序的根路径
    appDir: "some/path/trunk",
    // 脚本的根路径
    // 相对于程序的根路径
    baseUrl: "./js",
    // 打包输出到的路径
    dir: "../some/path/release",
    // 需要打包合并的js模块,数组形式,可以有多个
    // name 以 baseUrl 为相对路径,无需写 .js 后缀
    // 比如 main 依赖 a 和 b,a 又依赖 c,则 {name: 'main'} 会把 c.js a.js b.js main.js 合并成一个 main.js
    modules: [
        {name: 'main'}
        ...
    ]
    // 通过正则以文件名排除文件/文件夹
    // 比如当前的正则表示排除 .svn、.git 这类的隐藏文件
    fileExclusionRegExp: /^\./
}

然后运行:

node r.js -o config.js

这时 RequireJS Optimizer 就会:

  1. 把配置信息的 modules 下的所有模块建立好完整的依赖关系,再把相应的文件打包合并到 dir 目录
  2. 把所有的 css 文件中,使用 @import 语法的文件自动打包合并到 dir 目录
  3. 把其它文件复制到 dir 目录,比如图片、附件等等

我已经把 RequireJS 和 r.js 整套东西用到了 H5Slides 上。觉得蛮方便的。

不过工作中的前端开发工作并不是绝对理想化的,有些旧的项目,并不是 AMD 的模块化开发方式,而是传统的 js 程序,开发一个页面时可能需要一口气引入三到五个 css 文件、十来个 js 文件…… 上线的时候为了减少流量及 HTTP 请求数又需要把代码尽可能重用和合并。这个时候就需要一个方便快捷的打包工具帮助我们了,下面就介绍一下 RequireJS Optimizer 是如何完成这项工作的。

用到的几个关键参数 ​

说到这里,必须要额外介绍几个 RequireJS Optimizer 的参数了:

modules[i].include ​

modules: [
    {
        name: "main",
        include: ["d", "e"]
    }
]

这里的 include 字段提供了“强制建立依赖关系”的功能,也就是说,即使在 main.js 的代码里没有依赖 d.js 和 e.js,它们也会在合并代码的时候插入到 main.js 的前面

skipModuleInsertion ​

在介绍这个参数之前需要说明的是,RequireJS Optimizer 有一个很智能的功能,就是为没有写明 define(...) 函数的模块代码自动将其放入 define(...) 之中。如果我们写明:

skipModuleInsertion: true

则这种处理将会被取消。

onBuildRead ​

这个参数可以定义一个函数,在处理每个 js 文件之前,会先对文件的文本内容进行预处理。比如下面这个例子里,我会把 main.js 里的代码全部清除:

onBuildRead: function (moduleName, path, contents) {
    if (moduleName === 'main') {
        contents = '/* empty code */';
    }
    return contents;
}

巧妙应用到传统项目 ​

这时,我们的资源已经足够了。比如我现在的项目有:

1 个 html

  • index.html

代码:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Index</title>
        <link rel="stylesheet" href="css/a.css">
        <link rel="stylesheet" href="css/b.css">
    </head>
    <body>

        ...

        <script src="js/a.js"></script>
        <script src="js/b.js"></script>
        <script src="js/c.js"></script>
    </body>
</html>

2 个 css

  • css/a.css
  • css/b.css

3 个 js

  • js/a.js
  • js/b.js
  • js/c.js

1 个图片文件夹

  • images

合并 css 文件 ​

新建一个 css 文件,叫 css/main.css,内容为:

@import url(a.css);
@import url(b.css);

然后把 index.html 中的 2 个 <link> 标签改成一个

<link rel="stylesheet" href="css/main.css">

合并 js 文件 ​

合并 js 文件的步骤略复杂些。首先也是新建一个 js 文件,叫 js/main.js:

document.write('<script src="js/a.js"></script>');
document.write('<script src="js/b.js"></script>');
document.write('<script src="js/c.js"></script>');

然后把 index.html 中的 3 个 <script> 标签改成一个

<script src="js/main.js"></script>

接下来就是配置打包工具的时间了。

禁止自动补齐 define(...) 的头尾 ​

skipModuleInsertion: true

强制建立依赖 ​

modules: [{name: 'main', include: ['a', 'b', 'c']}]

这样打包出来的 main.js 是这样的:

// code from a.js
// code from b.js
// code from c.js
document.write('<script src="js/a.js"></script>');
document.write('<script src="js/b.js"></script>');
document.write('<script src="js/c.js"></script>');

打包时去掉多余的 js/main.js 的代码 ​

onBuildRead: function (moduleName, path, contents) {
    if (moduleName === 'main') {
        contents = '/* empty code */';
    }
    return contents;
}

这样的话,打包工具就会把 document.write(...) 的代码去掉,得到干净的

// code from a.js
// code from b.js
// code from c.js
/* empty code */

运行 node r.js -o config.js 就可以得到一个打包成功的项目了,并且打包前后的代码都可以正常运行

附件是这个项目例子的源代码:project.zip