- 构建工具
- 前端
【免费下载链接】brunch
🍴 Web applications made easy. Since 2011.
本文围绕当前仓库中的 brunch-with-chaplin-js 骨架 展开,讲解如何用 Brunch 作为构建工具、以 Chaplin 作为 Backbone 之上的"元框架",快速搭建一个目录结构规整、路由清晰、视图可复用的 HTML5 单页应用。读完本文,你将掌握该骨架的安装运行流程、brunch-config.js的打包配置、各目录的职责划分,以及 Mediator、Controller、View 与 Region 等核心机制的源码级实现细节,可以直接以此骨架作为自己项目的基础工程。
骨架定位:Brunch 构建 + Chaplin 架构的样板工程
brunch-with-chaplin-js是 Brunch 官方仓库中提供的一个项目骨架(skeleton / boilerplate),其 README 开篇即说明了定位:这是一个基于 Brunch 构建、采用 Chaplin 架构的 HTML5 应用样板。它要求 Brunch 1.7+,但在当前仓库的 package.json 中实际锁定的是brunch ~2.3.0,即 2.x 时代的配置写法。
骨架的架构选型非常明确:
- Brunch:负责文件的监听、编译、合并与产出(
public/目录完全自动生成); - Backbone:作为底层 MVC/MVP 库;
- Chaplin:作为运行在 Backbone 之上的"元框架",提供路由、控制器生命周期、视图管理与内存回收等约定;
- CommonJS 模块化:与官方 Chaplin Boilerplate 使用 AMD 不同,本骨架改用 CommonJS,README 中给出的理由是"更容易使用与调试",这也与 Brunch 的
require体系天然契合。
从 目录结构 可以看到,应用代码全部位于app/下,包含application.js、initialize.js、mediator.js、routes.js以及controllers/、models/、views/、lib/等子目录——这就是 Chaplin 约定的一套完整应用骨架。
快速开始:安装、依赖与运行
安装骨架
有两种方式获得该骨架:
- 手动克隆仓库,然后复制其中的
app/、brunch-config.js、package.json、bower.json等文件到你的项目; - 使用 Brunch 的 new 命令(推荐),直接以该骨架初始化项目:
brunch new gh:paulmillr/brunch-with-chaplin-jsbrunch new是 Brunch 内置的脚手架命令,会从指定的 GitHub 路径拉取骨架并生成项目,这正是 Brunch 生态中"用骨架秒建项目"的标准用法。
前置环境与依赖安装
骨架 README 给出的环境要求如下:
- Node.js:OS X 上可用
brew install node安装; - Brunch:
npm install -g brunch全局安装; - Bower:
npm install -g bower全局安装; - 最后在项目目录内安装依赖:
npm install & bower installnpm install会拉取 Brunch 编译插件与应用运行库,bower install则负责前端静态依赖(本骨架的 bower.json 仅依赖h5bp-helpers,用于引入 HTML5 Boilerplate 的辅助样式)。
值得注意的是,当前仓库的 package.json 已经把所有关键运行库都放进了dependencies:chaplin ~1.1.0、exoskeleton ~0.6.0(Backbone 的轻量替代品)、jquery ~2.2.0、lodash ~2.2.0、console-polyfill ~0.1.0与normalize.css ~3.0.3;而devDependencies则集中了全部 Brunch 编译插件:javascript-brunch、css-brunch、stylus-brunch、handlebars-brunch、uglify-js-brunch、clean-css-brunch、auto-reload-brunch以及brunch ~2.3.0本体。也就是说,在现代 npm 环境下仅执行npm install即可完成全部依赖安装。
开发与生产构建
骨架 README 给出了两条核心命令:
# 开发模式:监听文件变化并持续增量重建,同时启动 HTTP 服务器 # 服务器自带 pushState 支持,适合 HTML5 History API 路由 brunch watch --server # 生产模式:产出压缩(minified)后的构建结果 brunch build --productionbrunch watch --server会同时做两件事:一是持续监听app/目录,任何源码改动都会触发增量编译;二是启动一个内置 HTTP 服务器,并且支持 pushState,这正是 Chaplin 的 Rails 风格路由在浏览器端正常工作的前提——URL 的切换不再依赖 hash。brunch build --production会走压缩管线:JavaScript 交给uglify-js-brunch、CSS 交给clean-css-brunch,产出可直接部署的生产包。
package.json的scripts中也预置了快捷方式:npm start等价于brunch watch --server,npm test则对应brunch test。
目录使用约定
骨架 README 强调了两条重要的开发约定:
public/目录完全自动生成并由 HTTP 服务器直接伺服,不要手动编辑它,你的代码一律写在app/目录;app/assets/下的静态文件(图片、字体、以及index.html入口页)会在构建时原样复制到public/,用于存放不需要编译的资源。
配置解析:brunch-config.js 与打包策略
骨架的 brunch-config.js 是理解整个构建行为的关键,全文件内容如下:
exports.config = { files: { javascripts: { joinTo: { 'javascripts/app.js': /^app/, 'javascripts/vendor.js': /^(?!app)/ } }, stylesheets: { joinTo: 'stylesheets/app.css' }, templates: { joinTo: 'javascripts/app.js' } }, npm: { aliases: { backbone: 'exoskeleton' }, globals: { _cp: 'console-polyfill', $: 'jquery' }, styles: { 'normalize.css': ['normalize.css'] } } };逐项说明其作用:
files.javascripts.joinTo:定义了 JS 的两份产物。- 路径匹配
/^app/的源码(即app/下的业务代码)合并进public/javascripts/app.js; - 其余所有文件(node_modules 依赖等)合并进
public/javascripts/vendor.js。 - 这一"应用代码与第三方代码分离"的策略,既利于缓存(vendor 不常变),也便于调试时定位问题来源。
- 路径匹配
files.stylesheets.joinTo:所有 Stylus/CSS 统一合并为一个public/stylesheets/app.css。files.templates.joinTo:Handlebars 模板经handlebars-brunch预编译后,以 CommonJS 模块的形式注入javascripts/app.js,这就是源码里可以直接require('./templates/site')拿到模板函数的原因。npm.aliases:把backbone这一模块名映射到exoskeleton。由于 Chaplin 依赖 Backbone API,而骨架选用的 Backbone 兼容实现是 exoskeleton,通过 alias 可以让require('backbone')实际解析到 exoskeleton,无需改动任何业务代码。npm.globals:把$暴露为全局的 jQuery、把_cp暴露为全局的 console-polyfill,供非模块化代码直接使用。npm.styles:把normalize.css中的 CSS 文件纳入构建管线的样式合并。
这些配置共同构成了 Brunch 2.x 时代"一处配置、三线产出(app.js / vendor.js / app.css)"的典型打包方案。
应用启动链路:从 initialize 到路由分发
骨架的入口逻辑非常精简,但每一环都是 Chaplin 约定的关键点。
1. 启动入口 initialize.js
app/initialize.js 在 DOM ready 后实例化应用:
var Application = require('application'); var routes = require('routes'); $(function() { return new Application({ title: 'Brunch example application', controllerSuffix: '-controller', routes: routes }); });这里传入三个关键配置:
title:应用标题,Chaplin 会据此自动更新document.title;controllerSuffix:'-controller',它决定了路由home#index会被解析到名为home-controller的控制器模块——这是 Chaplin 的"约定优于配置"核心体现;routes:路由表函数。
2. 应用对象 application.js
app/application.js 通过 CommonJS 引入 Chaplin 并派生应用类:
var Chaplin = require('chaplin'); module.exports = Application = Chaplin.Application.extend({ // start: function() { // // 这里可以在启动前预取数据,再调用 super 正式启动 // this.constructor.__super__.start.call(this); // } })默认情况下无需覆写任何方法;注释中给出了一个常见扩展点:在start()中先异步拉取初始化数据,再调用super继续应用启动流程。
3. 中介者 mediator.js
app/mediator.js 只有一行:
var mediator = module.exports = Chaplin.mediator;它将 Chaplin 全局中介者导出为应用内模块。Mediator 是 Chaplin 跨模块通信的枢纽,配合 Publish/Subscribe 模式,控制器、视图、模型之间不需要互相持有引用即可收发事件,这是骨架 README 明确列出的核心特性之一。
4. Rails 风格路由 routes.js
app/routes.js 定义了 URL 到控制器动作的映射:
module.exports = function(match) { return match('', 'home#index'); };match('', 'home#index')表示根路径/交由home-controller的index动作处理。得益于controllerSuffix: '-controller',字符串'home'会自动解析为home-controller模块。新增页面时只需追加match('/xxx', 'controller#action')并在controllers/下新建对应文件即可,扩展路径非常直接。
控制器与视图协作:reuse、Region 与内存管理
控制器基类:跨页面复用的 Composition
app/controllers/base/controller.js 是所有控制器的基类:
var Chaplin = require('chaplin'); var SiteView = require('views/site-view'); module.exports = Chaplin.Controller.extend({ // 通过 Composition 在控制器之间持久化实例 beforeAction: function() { return this.reuse('site', SiteView); } });这里的reuse('site', SiteView)是 Chaplin 的 Composition 机制:名为site的视图实例一旦创建,就会在后续控制器切换时被复用而不是重建,从而让"站点外壳"(页头、页脚、布局容器)跨页面保持状态。注释明确说明:"Compositions 会在控制器之间持久化内容,你也可以用同样的方式持久化模型等。"
具体控制器:挂载头部视图与主区域视图
app/controllers/home/home-controller.js 演示了完整的控制器写法:
var Controller = require('controllers/base/controller'); var HeaderView = require('views/home/header-view'); var HomePageView = require('views/home/home-page-view'); module.exports = Controller.extend({ beforeAction: function() { this.constructor.__super__.beforeAction.apply(this, arguments); this.reuse('header', HeaderView, {region: 'header'}); }, index: function() { this.view = new HomePageView({region: 'main'}); } });beforeAction先调用父类以复用站点外壳,再把名为header的头部视图复用到header区域;index动作创建HomePageView并挂载到main区域——动作结束时控制器将this.view交给 Chaplin 的 Dispatcher 管理,页面切换时旧视图会被自动 dispose。
站点视图与区域(Region)机制
app/views/site-view.js 是整个应用的"壳":
var View = require('views/base/view'); module.exports = View.extend({ container: 'body', id: 'site-container', regions: { header: '#header-container', main: '#page-container' }, template: require('./templates/site') });container: 'body':视图渲染后插入body;regions:声明header与main两个命名区域,分别指向页面中的#header-container和#page-container容器。控制器通过{region: 'header'}/{region: 'main'}把子视图挂到对应区域,这就是 Chaplin 的 Region 机制——视图只认区域名,不关心容器选择器,布局与业务彻底解耦。
配合 site.hbs 模板,该骨架实现了 README 中"与官方 Chaplin Boilerplate 相比新增了 Header"的差异点。
内存管理与对象回收
骨架 README 将"严格的内存管理与对象回收(Strict memory management and object disposal)"列为重要特性。它在源码中的体现是:
- app/views/base/view.js 与 app/views/base/collection-view.js 均直接继承
Chaplin.View/Chaplin.CollectionView。Chaplin 的视图基类内置了dispose()生命周期:解除 DOM 事件绑定、移除子视图监听、注销 mediator 订阅,页面切换时 Dispatcher 会自动调用,避免事件监听泄漏; - 所有基类(view / collection-view / model / collection)集中放在
app/views/base/与app/models/base/,形成统一的继承入口,后续为"回收逻辑"添加自定义实现非常方便。
扩展基类与模板助手
应用级视图基类:模板注入
app/views/base/view.js 是业务视图的共同祖先:
var Chaplin = require('chaplin'); require('lib/view-helper'); module.exports = Chaplin.View.extend({ // 允许把 `template` 作为构造参数传入并保存为实例属性 optionNames: Chaplin.View.prototype.optionNames.concat(['template']), getTemplateFunction: function(){ return this.template; } });它做了一件很关键的事:通过扩展optionNames,让template可以作为构造参数直接传入(如new HomePageView({region: 'main'})之外再传template),并由getTemplateFunction()返回。业务视图(例如 home-page-view.js)只需声明template: require('./templates/home')即可渲染,无需关心模板编译细节。
由于CollectionView不继承这个应用级 View,collection-view.js 特意从View.prototype借用getTemplateFunction,保证列表视图同样能用模板渲染条目。
模型与集合基类:同步状态机
app/models/base/model.js 与 app/models/base/collection.js 分别继承Chaplin.Model与Chaplin.Collection。源码中保留了一段被注释的样板代码:通过_.extend(this, Chaplin.SyncMachine)混入同步状态机,并监听request/sync/error事件驱动beginSync/finishSync/unsync——这是 Chaplin 文档推荐的模型同步状态管理方式,骨架将其作为现成的扩展点留给开发者按需启用。
同时,集合基类设置了model: Model,声明集合元素类型;README 中提到的"带额外操作方法的集合(更智能的 change 事件)"与"集合视图(简便智能的列表渲染)"正是Chaplin.Collection与Chaplin.CollectionView提供的内置能力。
Handlebars 全局助手
app/lib/view-helper.js 通过Handlebars.registerHelper注册了三个全局助手:
with:增强原生的with块——当上下文为空时渲染inverse分支,避免对空对象取值报错;without:with的取反形态,空值渲染主分支;url:调用 app/lib/utils.js 的reverse(routeName, params),按路由名反向生成 URL——模板里写{{url 'home'}}即可得到对应路径,彻底告别硬编码链接。
由于该文件在视图基类中被require,因此所有业务模板都能直接使用这三个助手。
骨架的边界与自定义方向
阅读 README 时需要注意几个事实层面的限制:
- 不含测试环境:README 明确说明当前分支没有现成的测试环境,如需查看测试用法,应切换到
with-testsgit 分支(本骨架还提供brunch test脚本,可配合测试插件自行搭建)。 - 技术栈可替换:骨架默认使用 JavaScript + Stylus + Handlebars,README 说明"你可以改成任何你想要的组合",通过调整
brunch-config.js中的插件与joinTo配置即可换用 CoffeeScript、Sass、Jade 等。 - 认证支持:README 提到若需构建带登录鉴权的应用,可参考 chaplin-auth 提供的认证抽象,它与本骨架的 Chaplin 体系兼容。
- 参考实现:README 以 Ost.io 作为基于该骨架构建的示例应用。
- 浏览器支持:骨架宣称支持 IE8 及以上,并引入了
console-polyfill以补齐老浏览器的控制台能力。
许可证
骨架采用 MIT 许可证,版权声明见 README.md 末尾:Copyright (c) 2012 Paul Miller,以及 Copyright (c) 2012 Moviepilot GmbH、9elements GmbH 等。完整许可文本允许自由使用、复制、修改、合并、出版、分发、再许可与销售,但需保留上述版权声明,软件按"AS IS"提供且不附带任何明示或默示担保。
结语
brunch-with-chaplin-js骨架的价值在于把 Brunch 的构建便利与 Chaplin 的架构纪律组合在一起:brunch watch --server提供秒级增量编译与 pushState 服务器,Chaplin 则用 Routes、Controller、Dispatcher、Mediator、Region 与 dispose 生命周期把单页应用的复杂度组织得井井有条。本文已从安装运行、构建配置、启动链路、控制器/视图协作到基类扩展逐层拆解,读者可直接以 骨架目录 为起点,替换模板与样式,添加自己的路由与控制器,快速进入业务开发。
- 构建工具
- 前端
【免费下载链接】brunch
🍴 Web applications made easy. Since 2011.
相关推荐
oam-tools 中通过 Ascend Graph 接口在构图阶段采集性能数据的实战指南
oam tools 中通过 Ascend Graph 接口在构图阶段采集性能数据的实战指南 本文基于 CANN / oam tools 开源仓库的官方文档 do
构建工具前端agenix 实战部署:CI/CD 流水线中的密钥管理策略
agenix 实战部署:CI/CD 流水线中的密钥管理策略 在现代 DevOps 流程中,CI/CD 流水线的安全运行离不开可靠的密钥管理。 agenix 作为
Brunch - 快速构建静态网站和单页应用的工具
Brunch 快速构建静态网站和单页应用的工具 是一个现代化的构建工具,用于快速构建静态网站和单页应用程序(SPA)。它采用了模块化的方法,并且支持多种语言和技
构建工具前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考