编译期自动抽离大文本配置的核心是移出运行时内存,即将JSON/YAML/Markdown等静态内容在构建阶段提取为独立资源文件,再按需异步加载;Vite通过?raw导入和manualChunks控制输出,Webpack借助asset/resource实现物理分离,TS结合import type保障类型安全。

编译期自动抽离大文本配置,核心不是“删掉”,而是“移出运行时内存”——把 JSON、YAML、Markdown 等静态文本内容在构建阶段提取为独立资源文件(如 .json、.txt),再通过异步加载或 HTTP 请求按需读取。这样既保留了配置完整性,又避免了将几 MB 的文本硬塞进 JS bundle,导致首屏 JS 体积暴涨、解析阻塞、内存占用高。
为什么不能靠运行时 fetch 就完事?
单纯用 fetch('./config.json') 看似简单,但存在几个隐性问题:
- 开发阶段路径易错(Vite 的 public vs src,Webpack 的 public 目录 vs asset module)
- 没有类型提示和 IDE 支持(TS 无法推导结构,编辑器不校验字段)
- 无法参与构建分析(比如 Rollup/Vite 不知道这个文件是否被引用,可能被误删)
- 缺少缓存策略控制(比如想加 contenthash 却无法生效)
Vite 中实现编译期抽离(推荐方案)
Vite 原生支持 import 静态资源为字符串或 JSON,配合 build.rollupOptions.output.manualChunks 和自定义插件可精准控制输出位置与命名。
- 将大配置文件放在
src/assets/configs/下(如src/assets/configs/rules.json) - 在代码中用
import config from '@/assets/configs/rules.json?raw'(字符串)或直接import config from '@/assets/configs/rules.json'(JSON 模块) - 在
vite.config.ts中添加规则,确保这类文件不被打包进 JS:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
// 把所有 configs 目录下的 JSON 单独打包为 assets/configs/*.json
configs: (id) => id.includes('src/assets/configs/') && id.endsWith('.json')
}
}
}
}
})
构建后,rules.json 会出现在 dist/assets/configs/ 下,JS 中只保留一个轻量的动态 import 或 fetch 调用,不占内存。
Webpack 中实现编译期抽离(兼容 legacy 项目)
Webpack 需借助 asset/resource 类型 + CopyPlugin 或 file-loader(v5+ 推荐前者)来完成物理分离:
- 在
webpack.config.js的module.rules中添加:
{
test: /\.(json|yaml|yml|md)$/,
type: 'asset/resource',
generator: {
filename: 'configs/[name][ext]'
}
}
- 然后在源码中使用
import configPath from '@/configs/rules.json'—— 导入的是最终 URL 字符串,不是内容本身 - 运行时用
fetch(configPath)或import(configPath)(若为 JSON 模块)加载,内容始终不进入 JS bundle
进阶:带类型安全的 JSON 抽离(TS + Vite)
想保留 TypeScript 类型推导?可以结合 import type 和运行时加载:
- 新建
src/types/configs/rules.ts,定义接口:export interface RulesConfig { ... } - 源码中写:
import type { RulesConfig } from '@/types/configs/rules';+const config = await (await fetch('/configs/rules.json')).json() as RulesConfig; - 构建时 JSON 文件仍被单独输出,TS 类型在开发期全程可用,运行时零额外开销


















