浏览器原生支持模块导入,能否彻底告别构建工具


对于每一位前端开发者来说,下面这行代码再熟悉不过了:

import React from 'react';  
import _ from 'lodash';  

然而,如果我们把这行代码直接放到一个 <script type="module"> 标签里,并在浏览器中打开,迎接我们的将是一个冰冷的错误:

Uncaught TypeError: Failed to resolve module specifier "react". Relative references must start with "./", "../", or "/".

这个错误困扰了我们很多年。浏览器不认识像 react lodash 这样的“裸模块”(Bare Module
Specifier)。它只理解相对路径 ( ./utils.js ) 或绝对路径 ( /src/main.js )。

为了解决这个问题,我们引入了一整套复杂的“现代化”前端工具链:Webpack、Rollup、Vite 等构建工具。它们的核心任务之一,就是解析这些裸模块,从
node_modules 中找到对应的文件,然后将所有依赖打包(Bundle)成一个或多个浏览器可以理解的文件。

这个过程虽然有效,但也带来了新的问题:复杂的配置、漫长的启动和构建时间、难以调试的“黑盒”……

现在,一个原生、简洁的解决方案已经到来,它就是 ** Import Maps ** 。

什么是 Import Maps?

简单来说, ** Import Maps 是一种让浏览器理解“裸模块”的机制 ** 。它通过一个 JSON
对象,告诉浏览器:“当我们看到这个模块名时,请从这个 URL 地址去加载它。”

它就像是给浏览器的模块导入系统提供了一张“地图”或“别名簿”。

让我们来看一个最直观的例子。在我们的 HTML 文件中,我们可以这样定义一个 Import Map:

<!DOCTYPE html>  
<html>  
<head>  
 <title>Hello Import Maps!</title>  
 <!-- 1. 定义 Import Map -->  
 <script type="importmap">  
  {  
    "imports": {  
      "react": "https://esm.sh/react@18.2.0",  
      "lodash": "https://esm.sh/lodash-es@4.17.21",  
      "app/": "./src/app/"  
    }  
  }  
  </script>  
</head>  
<body>  
 <div id="root"></div>  
  
 <!-- 2. 像在 Node.js 环境中一样,直接使用裸模块导入 -->  
 <script type="module">  
    import React from 'react';  
    import { camelCase } from 'lodash';  
    import { sayHello } from 'app/utils.js'; // 也能映射路径前缀  
  
    console.log(React.version); // "18.2.0"  
    console.log(camelCase('hello world')); // "helloWorld"  
    sayHello(); // "Hello from utils!"  
  </script>  
</body>  
</html>  

一切都如此自然, ** 无需任何构建步骤,没有 Webpack,没有 Rollup,甚至不需要 node_modules
文件夹(对于纯浏览器依赖) ** 。我们只需要一个文本编辑器和一个现代浏览器。

那么,我们可以彻底告别构建工具了吗?

Import Maps 解决的是 ** 模块解析和加载 ** 的问题,但现代前端工程化远不止于此。构建工具仍然在以下几个关键领域扮演着不可或替代的角色:

  1. 代码转译
  2. 代码压缩、分割与打包
  3. 资源预处理

Import Maps
是一次意义深远的技术演进。它将前端开发中最基础、最核心的模块解析能力,从“工具领域”交还给了“浏览器平台”。这不仅让入门前端的门槛变得更低,也让经验丰富的开发者能够摆脱部分工具的束缚,回归到更纯粹的
Web 标准。

虽然我们短期内还无法完全抛弃构建工具,但 Import Maps 已经为我们打开了一扇通往“无构建”开发体验的大门。