Chrome 65中FileSaver.js saveAs返回undefined,ES6模块切换后失效求助
听起来你遇到的问题很典型——切换到ES模块后,FileSaver内部依赖的view(大概率是指浏览器的window对象)找不到了,导致saveAs提前返回,没法完成文件保存。结合你提到的Rollup打包流程,确实有可能是打包配置导致的环境变量异常,下面分情况给你分析和解决方案:
可能的原因&排查步骤
1. 导入方式不正确
先确认你是否用了正确的ES模块导入语法:
// 正确的解构导入 import { saveAs } from 'file-saver';
如果之前是全局引入(比如通过script标签),现在换成ES模块时误用了默认导入:
// 不推荐的方式,可能导致内部变量绑定异常 import FileSaver from 'file-saver'; FileSaver.saveAs(...)
这种情况下,FileSaver内部的view变量可能无法正确绑定到window对象,导致undefined。
2. Rollup打包时的环境注入缺失
FileSaver的核心逻辑依赖浏览器的window对象作为view上下文,但Rollup在处理ES模块时,尤其是打包成非IIFE格式(比如esm)时,可能会在严格模式下运行,不会自动暴露全局的window对象。这时候就需要手动注入window到FileSaver的依赖中:
解决方案:用@rollup/plugin-inject注入window
安装插件后,在Rollup配置文件中添加:
import inject from '@rollup/plugin-inject'; export default { input: 'src/index.js', output: { file: 'dist/bundle.js', format: 'esm' // 或者你用的其他格式 }, plugins: [ inject({ // 给FileSaver注入window对象 window: ['global/window', 'default'], }), ], };
这个插件会自动在FileSaver的代码中替换对window的引用,确保view变量能正确获取到浏览器环境。
3. Tree-shaking过度导致必要代码被移除
Rollup的tree-shaking功能可能会误把FileSaver内部和view相关的代码当成无用代码移除。你可以先临时禁用tree-shaking测试:
export default { // ...其他配置 treeshake: false };
如果禁用后问题解决,说明是tree-shaking的问题。这时候可以给FileSaver的导入添加/*#__PURE__*/注释,标记为纯函数避免被误删:
import { saveAs } from 'file-saver'; /*#__PURE__*/ saveAs(rasta, `chart.png`);
4. 异步返回值的类型问题
虽然你提到rasterize是重构后的SVG转Blob函数,但还是建议在调用saveAs前确认返回值类型:
var rasta = await rasterize(chart); console.log(rasta instanceof Blob); // 应该输出true if (rasta instanceof Blob) { saveAs(rasta, `chart.png`); } else { console.error('rasterize返回的不是Blob对象'); }
如果返回的不是Blob,也会导致FileSaver内部逻辑异常,提前返回。
总结
Rollup确实有可能是导致view为undefined的元凶——它的模块打包逻辑会改变代码的运行上下文,导致FileSaver依赖的全局window对象无法被正确获取。按照上面的步骤逐一排查,尤其是导入方式和Rollup的inject插件配置,应该能解决你的问题。
内容的提问来源于stack exchange,提问作者pmkro

