你以为加载个文本文件只能靠 fetch?今天 Import Text 把这件事彻底原生化了
你想在 JS 里加载一个 .txt 文件内容,最常见的写法是什么?
const res = await fetch('./readme.txt');
const text = await res.text();
两行,但它是异步的。你得处理 loading 状态,得确保文件真的被 fetch 到了,得处理 CORS,在 SSR 场景下还得换方案。
而现在,这事一行同步语句就搞定了:
import text from './readme.txt' with { type: 'text' };
console.log(text); // 直接就是字符串
这就是 Import Text,TC39 Stage 3 提案,Eemeli Aro 主导,Bun/Deno/Firefox Nightly 已落地。
它解决了什么问题
以前想在一个 JS 模块里直接引用一个文本文件,你绕不开这几条路:
方案一:fetch 异步
const res = await fetch('./template.html');
const html = await res.text();
永远是异步,代码里多一层 await,SSR 还要做特殊处理。
方案二:打包工具的 ?raw
import html from './template.html?raw';
这是 Vite/Rollup 的特殊语法,离开了 bundler 就跑不了,也没有类型提示。
方案三:Node fs 模块
import { readFileSync } from 'fs';
const content = readFileSync('./readme.txt', 'utf-8');
只能在 Node 端跑,浏览器完全不支持,路径计算还得配合 import.meta.url。
Import Text 把这事做成了语言级别的标准语法,跟 import json from './data.json' with { type: 'json' } 完全平级:
// 加载 Markdown 配置文件
import configMd from './config.md' with { type: 'text' };
// 加载 SVG 图标作为字符串
import svgIcon from './arrow.svg' with { type: 'text' };
// 加载 HTML partial
import partial from './partial.html' with { type: 'text' };
document.querySelector('div').setHTML(partial, { sanitizer: {} });
现在的支持情况
运行时:
- Bun:从 2024 年 4 月起原生支持,无需任何 flag
- Deno:2.4+ 支持,需
--unstable-raw-importsflag - Firefox Nightly:153.0a1 已支持
- Chrome/Safari:还在路上
Node.js:26.5.0 实验性支持,需 --experimental-import-text flag。
Bundler 层面:Vite 用户可以用 vite-import-attributes 插件将 with { type: 'text' } 语法转译成 Vite 自己的 ?raw 查询参数,在浏览器环境中提前落地支持。
也就是说:现在在 Bun 里可以直接跑,在 Deno 加个 flag 可以用,在 Vite 项目里装个插件全浏览器都支持。
和 JSON 模块是同一套设计
Import Text 不是拍脑袋想出来的新语法。它是 Import Attributes 体系的一部分,和你已经用得很熟的 JSON 模块是一套设计:
// JSON 模块 —— 2019 年落地
import data from './data.json' with { type: 'json' };
// 文本模块 —— Import Text,Stage 3
import text from './readme.txt' with { type: 'text' };
// 字节模块 —— Import Bytes,同步推进中
import bytes from './image.png' with { type: 'bytes' };
Import Attributes 体系的核心语义是:告诉运行时「这个被导入的东西不是 JS,按它的类型来处理」。文本文件导出一个字符串,JSON 文件导出一个对象,bytes 导出一个 Uint8Array,各是各的类型,编译器/bundler/运行时各司其职。
适合哪些场景
文档类站点:把 Markdown/SVG 作为静态资源 import 进来,不用 fetch,不用担心路径问题。
配置内联:把 YAML/TOML 配置文件 import 进来,在打包时就能拿到字符串,SSR 场景也能用。
代码展示:文档站里要展示源码,把源文件直接 import 进来渲染,不用写死字符串。
SVG 图标库:把 SVG 作为字符串导入,在运行时做 DOM 操作或者动态替换颜色,不用走 img 标签绕路。
下一步
如果你在用 Bun,现在就可以直接用,无需任何配置:
# index.ts
import readme from './readme.txt' with { type: 'text' };
console.log(readme);
bun run index.ts
如果你在用 Vite,装一个转换插件:
deno add jsr:@nick/vite-import-attributes
然后在 vite.config.ts 里加一行插件,把 with { type: 'text' } 语法转成 Vite 的 ?raw:
import viteImportAttributes from 'vite-import-attributes';
export default {
plugins: [viteImportAttributes()],
};
Chrome 和 Safari 正式支持只是时间问题。这个语法的设计已经非常成熟,Bun 跑了一年半没有 breaking change,Deno 和 Firefox 跟进,方向已经很明确了。
你的项目里,还在用 ?raw 或者 readFileSync 加载文本吗?
评论区
登录后可评论。