Vue3项目中,Vite/Rollup是否有钩子处理自动复制的静态资源?
如何在Vite构建阶段拦截public目录资源复制并做自定义处理?
我正在开发Vue3应用,Vite会自动复制项目根目录~/public文件夹下的所有静态资源文件。我希望在vite build构建阶段,获取正在复制的资源信息并执行自定义处理函数(比如给指定文件的占位符插值),理想实现的伪代码如下:
示例伪代码
/some/hook/or/plugin.js
export function observe(pathname, source) { // 拦截 ~/public/assets/listings.js 文件 if (pathname !== 'assets/listings.js') return source; return utilities.interpolate(source)({ tokenX: 'value to supplant in file' }); };
~/vite.config.js
export default defineConfig({ plugins: [ vue() ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, staticAssetStuff: { hooks: [ observe, ] } });
示例 ~/public/assets/listings.js
export default [ 'This is a listing where {tokenX} needs to get interpolated', ...more ];
背景说明
我需要将特定值插值到~/public/assets/listings.js的占位符中,因为有一个必须留在public目录的静态脚本需导入该文件,且操作必须在打包完成后进行。我查阅了Vite和Rollup的大量文档,未找到可直接挂钩资源复制阶段的方法;目前考虑在package.json中编写postbuild脚本遍历~/dist目录处理资源,但想确认是否存在更贴合构建流程的钩子实现方式。
实现方案:用Vite插件的writeBundle钩子直接处理
可以实现,不需要依赖postbuild脚本,通过自定义Vite插件的writeBundle钩子即可在构建完成后精准处理目标文件:
1. 编写自定义Vite插件
// src/plugins/publicAssetInterpolation.js import fs from 'fs'; import path from 'path'; export default function publicAssetInterpolation() { return { name: 'public-asset-interpolation', // 生产构建完成后执行 writeBundle(options) { const distDir = options.dir; const targetFilePath = path.join(distDir, 'assets/listings.js'); if (fs.existsSync(targetFilePath)) { let content = fs.readFileSync(targetFilePath, 'utf-8'); // 替换占位符,这里可替换为你的自定义处理逻辑 content = content.replace(/\{tokenX\}/g, 'value to supplant in file'); fs.writeFileSync(targetFilePath, content, 'utf-8'); console.log(`已完成 ${targetFilePath} 的插值处理`); } } }; }
2. 在Vite配置中引入插件
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import publicAssetInterpolation from './src/plugins/publicAssetInterpolation'; import { fileURLToPath } from 'url'; export default defineConfig({ plugins: [ vue(), publicAssetInterpolation() // 加入自定义插件 ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } });
3. (可选)开发环境同步处理
如果需要在开发环境也让占位符生效,可在插件中添加configureServer钩子拦截请求:
// 在上述插件中新增configureServer钩子 configureServer(server) { const publicDir = path.resolve(server.config.root, 'public'); const targetFilePath = path.join(publicDir, 'assets/listings.js'); // 拦截请求,返回处理后的内容 server.middlewares.use((req, res, next) => { if (req.url === '/assets/listings.js') { let content = fs.readFileSync(targetFilePath, 'utf-8'); content = content.replace(/\{tokenX\}/g, 'value to supplant in file'); res.setHeader('Content-Type', 'application/javascript'); res.end(content); return; } next(); }); }
方案优势
相比postbuild脚本,用Vite插件钩子更贴合构建流程,无需额外配置脚本命令,还能统一覆盖开发和生产环境的处理逻辑。
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

