无构建开发
在现代 Web 开发中,随着浏览器对 ES 模块和现代 CSS 特性的普遍支持,我们可以考虑一种全新的开发方式:无构建开发(No Build Development)。这种方式避免了复杂的构建工具链,直接利用浏览器的原生能力。
本章节的核心理念受到 DHH 文章 “You can’t get faster than No Build” 的启发。
核心理念
“无构建“并不意味着完全没有任何处理步骤,而是指:
- 避免复杂的编译过程:不需要 Webpack、Rollup、esbuild 等打包工具
- 利用原生特性:充分使用浏览器已经支持的现代 JavaScript 和 CSS 特性
- 简化开发流程:减少构建时间,提升开发体验
“You can’t get faster than No Build” - DHH
技术基础
ES 模块原生支持
现代浏览器已经原生支持 ES 模块,无需编译:
<!DOCTYPE html>
<html>
<head>
<script type="module" src="./main.js"></script>
</head>
</html>
// main.js
import { utils } from './utils.js';
import { API_BASE } from './config.js';
console.log(utils.formatDate(new Date()));
Import Maps
Import Maps 让我们可以使用裸模块说明符,无需打包工具:
<script type="importmap">
{
"imports": {
"lodash": "https://cdn.skypack.dev/lodash-es",
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js",
"@/": "./src/"
}
}
</script>
// 现在可以直接导入
import _ from 'lodash';
import { createApp } from 'vue';
import { helper } from '@/utils/helper.js';
现代 CSS 特性
CSS 嵌套和自定义属性等特性已被广泛支持:
:root {
--primary-color: #3498db;
--border-radius: 4px;
}
.card {
background: white;
border-radius: var(--border-radius);
.header {
color: var(--primary-color);
&:hover {
opacity: 0.8;
}
}
}
实践案例
基础项目结构
project/
├── index.html
├── main.js
├── styles.css
├── src/
│ ├── components/
│ │ ├── header.js
│ │ └── footer.js
│ ├── utils/
│ │ └── helpers.js
│ └── api/
│ └── client.js
入口文件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>无构建开发示例</title>
<link rel="stylesheet" href="./styles.css">
<script type="importmap">
{
"imports": {
"@/": "./src/",
"lit": "https://cdn.skypack.dev/lit"
}
}
</script>
<script type="module" src="./main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
组件模块
// src/components/header.js
export class HeaderComponent {
constructor(title) {
this.title = title;
}
render() {
return `
<header class="app-header">
<h1>${this.title}</h1>
</header>
`;
}
}
// main.js
import { HeaderComponent } from '@/components/header.js';
import { initializeApp } from '@/utils/helpers.js';
const header = new HeaderComponent('我的应用');
document.getElementById('app').innerHTML = header.render();
initializeApp();
优势与限制
优势
-
极速开发体验
- 无编译等待时间
- 文件保存即刷新
- 调试更直观
-
简化的工具链
- 减少依赖包
- 降低配置复杂度
- 更少的出错点
-
原生性能
- 浏览器优化的模块加载
- HTTP/2 多路复用优势
- 按需加载天然支持
限制与考虑
-
兼容性要求
- 需要支持 ES 模块的现代浏览器
- Import Maps 的支持相对较新
-
开发约束
- 不能使用需要编译的语法(JSX、TypeScript)
- 第三方库需要有 ES 模块版本
-
生产环境
- 可能需要 HTTP/2 支持
- 文件数量较多时的网络开销
适用场景
适合的项目
- 原型开发:快速验证想法
- 小型项目:复杂度不高的应用
- 教学演示:减少学习曲线
- 内部工具:控制运行环境的场景
不适合的场景
- 大型团队项目:需要严格的类型检查和规范
- 复杂框架应用:依赖大量编译时优化
- 向后兼容要求:需要支持旧版浏览器
工具支持
开发服务器
简单的 HTTP 服务器即可,支持 ES 模块:
# Python
python -m http.server 8080
# Node.js
npx http-server
# 或使用支持模块的开发服务器
npx es-dev-server
编辑器配置
现代编辑器已经很好地支持原生 ES 模块:
// .vscode/settings.json
{
"typescript.preferences.includePackageJsonAutoImports": "on",
"typescript.suggest.autoImports": true
}
与传统构建的对比
| 方面 | 无构建开发 | 传统构建 |
|---|---|---|
| 启动速度 | 即时 | 需要编译时间 |
| 热更新 | 原生支持 | 需要工具支持 |
| 调试体验 | 直接调试源码 | 需要 Source Map |
| 部署复杂度 | 简单 | 需要构建步骤 |
| 文件大小 | 未压缩 | 优化压缩 |
| 兼容性 | 现代浏览器 | 可配置目标 |
总结
无构建开发代表了 Web 开发的一种回归:回归到 Web 平台的原生能力。随着浏览器对现代标准的支持越来越完善,这种开发方式在特定场景下提供了极佳的开发体验。
选择是否使用无构建开发,需要根据项目的具体需求、团队技能和目标用户来权衡。它不是银弹,但确实为我们提供了一个值得考虑的选择。
最好的构建工具就是不需要构建工具。