No Zuo No Die Why You Try

RequireJs 初哥

最近在弄前端打包的东西, 发现有些很基础的东西想弄好还是不那么容易的。


其实也有蛮多框架可以用的, 随便看了下, 国外现在挺火的 webpack, 或者是国内可能已经有点过气的度娘的 fis, 应该都是挺不错的.

但我是个比较懒的人, 不是太轻的东西, 嚼不透的话还是不敢随随便便就拿来用, 学一样东西啦, 读一遍文档都是挺累人的. 还是稍微花点时间折腾一下 RequireJs 自己的东西好了.

RequireJs 自己就包含了专门的打包工具 r.js, 代码有两万多行 (还好至少没更多第三方依赖了), 出点小问题的话嚼一下应该还是能嚼的动的. 它的文档组织的不是我喜欢的样子, 没法当手册来用, 大部分的说明都放到一个配置文件的备注上了, 读起来有点累人.

我的需求其实蛮简单的, 就是想把一些文件打一起, 然后另外一些文件要剥离开, 避免一开始就要被迫载入所有的东西, 当然, 哪些文件需要放一起, 最好能够有脚本参与的空间, 毕竟很多原有的代码不是遵循 AMD 规范的依赖约定, 或者是在上面有加了些自己所约定的内容, 有脚本的话一切会简单很多.


无聊

require 已经提供了一些例子, 比如这个

https://github.com/requirejs/example-multipage

演示了个简单的多页面项目,大致上可以实现

这是一个很不错的入口, 因为它足够简单, 没有什么累赘和多余的东西, 一目了然.

但是我没找到一个能满足我需求的足够简单的例子. (也许只是我搜索的姿势不太对)

所以后来我撸了下面这个示例项目

https://github.com/lwr/example-onepage-lazy-load

希望对一些同样不想用框架(或者想造自己轮子)的后来者提供一些帮助.


折腾

需求前面已经说过了, 我就简单整理一下为了达成预期目标所遇到的一些坑以及所采取了的应对手段

== 首先是 option 模块化的问题 ==

r.js 命令行支持的 -o 参数支持的选项文件既不是一个简单的 json 文件也不是一个可导入的标准 CommonJS 模块, 查了 r.js 的源代码才知道, 好家伙那原来是一个 eval 语句, 虽然有点 dirty, 但至少灵活性是有了

由于主要的打包工具是 grunt, 我希望这个配置文件是通用的, 既可以在 grunt 或其它同样是基于 NodeJS 的工具 (比如 gulp) 能够直接以 CommonJS 模块导入, 也可以直接用于 r.js 命令行.

所以就有了下面这些 hack (也不完全是 hack 了)

== modules 配置的生成问题 ==

选项文件模块化之后,这个问题就很好解决了, 在例子里面, modules 配置 (决定最终生成几个 js 文件的) 是 hardcode 的, 也就是说, 即使是无法模块化的 json 文件都能简单的配置.

我们实际的项目是用了点脚本, 递归扫描了下各个模块目录, 生成一个模块包含序列, 有脚本参与的话这些都是很容易做到的

== bundles config ==

了解这个问题之前建议先读一下 RequireJs 文档的这部分

http://requirejs.org/docs/api.html#config-bundles

由于几个模块 (示例里面分别是 modules/1, modules/2, modules/3, modules/4) 的同名的 js 文件在打包后已经被删除, 在需要(动态)加载这些 AMD 模块的时候, 由于文件还没载入, RequireJs 将触发同名的 js 文件载入来加载模块定义, 于是就产生了久违的 404

解决办法就是在配置文件中插入一段 bundles config, 可以利用 onBuildWrite 回调函数来达成 (r.js 的配置示例文件中有说明这个函数的用法, 每个模块在输出的时候可以做一些额外的修改, 比如我们这里就是插入一点配置信息), 插入的是这么一段代码

require.config({
    bundles : {
        "m12": ["modules/1", "modules/3"],
        "m34": ["modules/3", "modules/4"]
    }
});

当然, 这段代码是不需要 hardcode 的, 完全可以从 modules 配置里面反向导出来


结语

所有(配置)源码也只有几十行代码, 其实也没啥好说的, 看两眼然后运行一下应该都不难知道是咋回事, 虽然折腾的时候还是要费不少功夫, 但不折腾一下又怎么知道世界有多美(can)丽(ku)呢?