Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

无构建开发

在现代 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();

优势与限制

优势

  1. 极速开发体验

    • 无编译等待时间
    • 文件保存即刷新
    • 调试更直观
  2. 简化的工具链

    • 减少依赖包
    • 降低配置复杂度
    • 更少的出错点
  3. 原生性能

    • 浏览器优化的模块加载
    • HTTP/2 多路复用优势
    • 按需加载天然支持

限制与考虑

  1. 兼容性要求

    • 需要支持 ES 模块的现代浏览器
    • Import Maps 的支持相对较新
  2. 开发约束

    • 不能使用需要编译的语法(JSX、TypeScript)
    • 第三方库需要有 ES 模块版本
  3. 生产环境

    • 可能需要 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 平台的原生能力。随着浏览器对现代标准的支持越来越完善,这种开发方式在特定场景下提供了极佳的开发体验。

选择是否使用无构建开发,需要根据项目的具体需求、团队技能和目标用户来权衡。它不是银弹,但确实为我们提供了一个值得考虑的选择。

最好的构建工具就是不需要构建工具。