THIS_IS_UNDEFINED — это предупреждение Rollup,
возникающее в момент анализа модулей, когда сборщик обнаруживает
использование this в контексте ES-модуля, где значение
this гарантированно равно undefined. Это
предупреждение относится не к синтаксической ошибке, а к потенциальному
расхождению поведения между различными форматами модулей и окружениями
исполнения.
В классическом JavaScript поведение this зависит от
способа вызова функции и режима выполнения. Однако ES-модули вводят
фиксированное поведение: в верхнеуровневом контексте значение
this всегда равно undefined.
// ES module
console.log(this); // undefined
Это отличается от CommonJS-модулей, где this на верхнем
уровне указывает на module.exports:
// CommonJS
console.log(this === module.exports); // true
Именно это различие является источником проблем при сборке через Rollup, когда код из разных модульных систем объединяется в единый бандл.
Rollup генерирует предупреждение THIS_IS_UNDEFINED,
если:
this в верхнеуровневом
контексте ES-модуляthis не может быть корректно
восстановлен после транспиляцииТипичный пример:
// module.js
console.log(this.value);
После интерпретации как ES module this становится
undefined, и обращение к this.value приводит к
ошибке выполнения.
Rollup выполняет статический анализ кода и стремится выявить
конструкции, которые изменят поведение при бандлинге. В случае
this проблема заключается в том, что:
this может иметь осмысленное значение
(CommonJS, legacy-код)undefinedТаким образом предупреждение сигнализирует о потенциально сломанной логике после сборки.
ESM всегда исполняются в strict mode. Это ключевой момент:
'use strict';
function test() {
console.log(this); // undefined
}
Даже если в исходном коде ожидалось глобальное this, в
модульной системе оно отсутствует.
Rollup учитывает это поведение и считает любые неявные обращения к
this потенциально опасными.
Многие старые библиотеки используют this как ссылку на
module.exports:
this.exportedValue = 123;
После преобразования в ES module через Rollup:
this становится undefinedКод, рассчитанный на браузер без модулей:
this.alertMessage = "hello";
В модуле такое поведение ломается.
При использовании Babel или plugin-commonjs возможны ситуации, когда:
this не заменён на корректную переменнуюRollup анализирует AST и определяет:
this.somethingthisЕсли формат гарантирует this === undefined, генерируется
предупреждение:
(!) THIS_IS_UNDEFINED
src/module.js
`this` has been rewritten to `undefined`
Наиболее строгий вариант:
this всегда undefinedПоведение ближе к Node.js:
this может указывать на
module.exportsЗависит от обёртки:
this привязывается к глобальному объектуВ некоторых случаях Rollup может автоматически заменить
this:
// исходник
this.value
// результат
undefined.value
или
var _this = undefined;
_this.value;
Такая трансформация подчёркивает проблему: исходное поведение невозможно корректно сохранить.
Наиболее надёжный подход — исключение this из логики
модуля:
export const value = 123;
вместо:
this.value = 123;
Если this использовался как объект состояния:
function createModule(ctx) {
ctx.value = 123;
}
Стрелочные функции не имеют собственного this, что часто
усиливает проблему:
const fn = () => {
console.log(this);
};
Замена:
function fn() {
console.log(this);
}
Но в ES module это всё равно будет undefined, поэтому
важно не полагаться на this вообще.
Rollup позволяет сохранить контекст модуля:
export default {
output: {
preserveModules: true
}
}
или через moduleContext:
export default {
moduleContext: (id) => {
if (id.includes('legacy')) {
return 'window';
}
}
}
Это позволяет явно задать значение this для конкретных
модулей.
Плагин преобразования CommonJS может частично эмулировать
this:
require()-модули сохраняют поведение
module.exportsthisПри использовании транспиляции:
this = undefinedmodules: false сохраняет оригинальную
структуру, но не гарантирует контекстВ результате предупреждение может появляться на этапе Rollup даже при корректном исходном TypeScript-коде.
this.instance = new Service();
После сборки:
this теряет значениеthis.api = {};
this.api.method = fn;
В ESM становится невалидным.
this.cache ||= compute();
При this = undefined ломается вся логика
кеширования.
Rollup позволяет включить подробные предупреждения:
onwarn(warning, warn) {
if (warning.code === 'THIS_IS_UNDEFINED') {
console.log(warning.id, warning.frame);
}
warn(warning);
}
Это помогает локализовать места, где this используется
неявно.
Основная причина появления THIS_IS_UNDEFINED — смешение
двух моделей модулей:
thisRollup строго придерживается ES module semantics, поэтому любые попытки использовать старую модель поведения приводят к предупреждениям.
Ключевое различие:
this динамический, зависит от вызоваthis фиксирован и равен
undefinedRollup не пытается «угадать» поведение, а явно сигнализирует о несовместимости.
THIS_IS_UNDEFINED следует воспринимать как
индикатор:
В рамках Rollup это не косметическое предупреждение, а сигнал о потере семантики исполнения после сборки.