疑难解答
如果您遇到问题,请尝试在 Rollup Discord 上讨论该问题,或在 Stackoverflow 上发布问题。如果您发现错误,或者 Rollup 无法满足您的需求,请尝试 提出问题。最后,您可以尝试在 Twitter 上联系 @RollupJS。
避免使用 eval
您可能已经知道 'eval
很邪恶',至少有些人是这么认为的。但它对 Rollup 来说尤其有害,因为它的工作原理 - 与其他模块捆绑器不同,其他模块捆绑器将每个模块包装在一个函数中,而 Rollup 将所有代码放在同一个作用域中。
这更有效率,但意味着每次使用 eval
时,共享作用域都会被 '污染',而使用不同的捆绑器,未使用 eval 的模块不会被污染。混淆器无法混淆污染代码中的变量名,因为它无法保证要评估的代码不会引用这些变量名。
此外,它存在安全风险,因为恶意模块可以使用 eval('SUPER_SEKRIT')
访问另一个模块的私有变量。
幸运的是,除非您确实打算让评估的代码访问局部变量(在这种情况下,您可能做错了什么!),否则您可以通过以下两种方式之一实现相同的效果
eval2 = eval
简单地 '复制' eval
为您提供了一个执行完全相同操作的函数,但它在全局作用域中运行,而不是在局部作用域中运行
var eval2 = eval;
(function () {
var foo = 42;
eval('console.log("with eval:",foo)'); // logs 'with eval: 42'
eval2('console.log("with eval2:",foo)'); // throws ReferenceError
})();
new Function
使用 Function 构造函数 从提供的字符串生成一个函数。同样,它在全局作用域中运行。如果您需要重复调用该函数,这比使用 eval
快得多。
Tree-shaking 似乎不起作用
有时,您最终会在捆绑包中得到一些似乎不应该存在的代码。例如,如果您从 lodash-es
导入一个实用程序,您可能希望获得该实用程序正常工作所需的最小代码量。
但是 Rollup 必须对它删除的代码保持谨慎,以确保最终结果能够正确运行。如果导入的模块似乎具有副作用,无论是对您正在使用的模块部分还是对全局环境,Rollup 都会谨慎行事并包含这些副作用。
由于像 JavaScript 这样的动态语言中的静态分析很困难,因此偶尔会出现误报。Lodash 是一个很好的例子,它看起来有很多副作用,即使在它没有的地方也是如此。您通常可以通过导入子模块来缓解这些误报(例如,import map from 'lodash-es/map'
而不是 import { map } from 'lodash-es'
)。
Rollup 的静态分析会随着时间的推移而改进,但它永远不会在所有情况下都完美 - 这就是 JavaScript 的本质。
错误: "[name] 未由 [module] 导出"
有时您会看到这样的错误消息
'foo' 未由 bar.js 导出(由 baz.js 导入)
导入声明必须在导入的模块中具有相应的导出声明。例如,如果您在模块中具有 import a from './a.js'
,并且 a.js 没有 export default
声明,或者 import {foo} from './b.js'
,并且 b.js 没有导出 foo
,则 Rollup 无法捆绑代码。
此错误经常发生在由 rollup-plugin-commonjs 转换的 CommonJS 模块中,此包已弃用,不再维护。请使用 @rollup/plugin-commonjs。
错误: "this 未定义"
在 JavaScript 模块中,this
在顶层(即函数外部)为 undefined
。因此,Rollup 会将任何 this
引用重写为 undefined
,以便最终行为与模块获得原生支持时发生的行为相匹配。
this
有时有其他含义的有效原因。如果您在捆绑包中遇到错误,您可以使用 options.context
和 options.moduleContext
来更改此行为。
警告: "源映射可能不正确"
如果您使用捆绑包生成源映射(sourcemap: true
或 sourcemap: 'inline'
),但您使用了一个或多个插件来转换代码而没有为转换生成源映射,您将看到此警告。
通常,插件只会省略源映射,如果它(插件,而不是捆绑包)配置了 sourcemap: false
- 所以您需要做的就是更改它。如果插件没有生成源映射,请考虑向插件作者提出问题。
警告: "将 [module] 视为外部依赖项"
Rollup 默认情况下只会解析相对模块 ID。这意味着像这样的导入语句…
import moment from 'moment';
…不会导致 moment
包含在您的捆绑包中 - 相反,它将是一个在运行时所需的外部依赖项。如果这就是您想要的,您可以使用 external
选项来抑制此警告,这会明确您的意图
// rollup.config.js
export default {
entry: 'src/index.js',
dest: 'bundle.js',
format: 'cjs',
external: ['moment'] // <-- suppresses the warning
};
如果您确实想将模块包含在捆绑包中,您需要告诉 Rollup 如何找到它。在大多数情况下,这是一个使用 @rollup/plugin-node-resolve 的问题。
一些模块,如 events
或 util
,是内置在 Node.js 中的。如果您想包含这些模块(例如,以便您的捆绑包在浏览器中运行),您可能需要包含 rollup-plugin-polyfill-node。
错误: "EMFILE: 打开的文件过多"
对于大型项目,您可能会在 macOS 上以监视模式运行 Rollup 时遇到 EMFILE 错误。如果您遇到此问题,禁用 FSEvents 可能会消除此问题
// rollup.config.js
export default {
...,
watch: {
chokidar: {
useFsEvents: false
}
}
};
错误: JavaScript 堆内存不足
由于 Rollup 需要同时将所有模块信息保存在内存中,以便能够分析与 tree-shaking 相关的副作用,因此捆绑大型项目可能会达到 Node 的内存限制。如果发生这种情况,通过以下方式运行 Rollup 可以帮助增加此限制
node --max-old-space-size=8192 node_modules/rollup/dist/bin/rollup -c
根据需要增加 --max-old-space-size
。请注意,此数字可以安全地超过您的可用物理内存。在这种情况下,Node 将根据需要开始将内存分页到磁盘。
您可以通过使用动态导入引入代码拆分、仅导入特定模块而不是整个依赖项、禁用源映射或增加交换空间的大小来减少内存压力。
错误: Node 尝试将您的配置文件加载为 CommonJS,即使它很可能是 ES 模块
默认情况下,Rollup 将使用 Node 的原生模块机制来加载您的 Rollup 配置。这意味着如果您在配置中使用 ES 导入和导出,您需要在 package.json
文件中定义 "type": "module"
,或者为您的配置使用 .mjs
扩展名。有关更多信息,另请参见 配置文件 和 使用原生 Node ES 模块时的注意事项。