如何对上传结果生成 manifest 并注入 HTML
解读
在国内前端工程化面试中,这道题考察的是**“构建产物版本化管理”与“资源自动注入”**两大能力。
面试官真正想听的是:
- 你能否用 Grunt 把上传 CDN 后返回的 URL 列表固化成一份 manifest(通常是 JSON);
- 再把 manifest 中的指纹文件名自动注入到 HTML,确保用户拿到的是最新资源,同时保留灰度回滚能力。
回答时务必体现**“国内 CDN 路径规则”“缓存击穿策略”“Grunt 插件链式协作”**这三点,否则会被认为“只会配置,不会落地”。
知识点
- grunt-filerev:给静态资源加 md5 指纹,避免 CDN 缓存
- grunt-upload-cdn(或自研插件):把带指纹的文件上传到国内云厂商(OSS、COS、KSS),返回“cdnPath+key”映射表
- grunt-manifest-json:将上传结果写成 manifest.json,格式需包含文件逻辑名→CDN 绝对路径的键值对,方便服务端灰度
- grunt-replace 或 grunt-inline-cdn:读取 manifest,把 HTML 里形如
__CDN__/js/index.js的占位符替换成真实 CDN 地址 - grunt-contrib-watch + grunt-contrib-livereload:开发阶段本地不注入 CDN,保证调试速度;仅在生产构建流程触发上传与注入
- 版本回滚策略:manifest 文件随包发布到服务器,运维只需回滚 manifest 即可瞬间切换静态资源版本,无需重新上传 CDN
答案
- 安装核心链
npm i -D grunt-filerev grunt-upload-cdn grunt-manifest-json grunt-replace
- Gruntfile 关键片段
grunt.initConfig({
filerev: {
options: { algorithm: 'md5', length: 8 },
dist: { src: ['dist/**/*.{js,css,png}'] }
},
upload_cdn: {
dist: {
options: {
provider: 'aliyun-oss', // 国内主流
accessKeyId: '<%= env.ALI_KEY %>',
secretAccessKey: '<%= env.ALI_SECRET %>',
bucket: 'static-xyz',
region: 'oss-cn-hangzhou',
// 上传成功后把结果写到 grunt.config('cdnMap')
callback: function(result) {
grunt.config.set('cdnMap', result);
}
},
files: [{ expand: true, cwd: 'dist', src: '**/*' }]
}
},
manifest_json: {
dist: {
options: { space: 2 },
src: '<%= grunt.config("cdnMap") %>',
dest: 'dist/manifest.json'
}
},
replace: {
html: {
options: {
patterns: [{
match: /__CDN__\/([^'"\s]+)/g,
replacement: function(_, logicName) {
var map = grunt.file.readJSON('dist/manifest.json');
return map[logicName] || grunt.fail.warn('找不到 '+logicName);
}
}]
},
files: [{ expand: true, cwd: 'dist', src: '*.html', dest: 'dist/' }]
}
}
});
grunt.registerTask('build', [
'clean:dist',
'filerev',
'upload_cdn',
'manifest_json',
'replace:html'
]);
- 运行
ALI_KEY=xxx ALI_SECRET=xxx grunt build
构建结束后,dist 目录出现 manifest.json,HTML 中的 __CDN__/js/index.js 被替换成 //static-xyz.oss-cn-hangzhou.aliyuncs.com/js/index.3f4a2b8c.js,完成**“上传→生成→注入”**闭环。
拓展思考
- 灰度发布:把 manifest.json 上传到配置中心(Nacos、Apollo),网关按用户维度下发不同版本 manifest,实现**“静态资源灰度”**,这是国内大厂常用方案
- 多环境隔离:利用 grunt-env 区分 daily、pre、prod,不同环境对应不同 CDN 域名,避免测试资源污染线上缓存
- 雪崩降级:若 CDN 异常,可在 manifest 里增加
fallback: true字段,Node 中间件读取后自动把资源域名切回源站,保证可用性 - 增量上传:grunt-upload-cdn 支持 etag 比对,只传变更文件,节省 70% 流量,适合日构建 1000+ 文件的大型业务
- 合规审计:国内金融、政企项目要求“静态资源可溯源”,可在 manifest 中追加
gitCommit字段,方便等保测评时快速定位版本