Фу, мне удалось заставить его работать.Вот что нужно сделать:
В конфигурации веб-пакета:
Установить цель для 'node'
config.target = 'node';
Установите целевую библиотеку вывода на commonjs2
config.output.libraryTarget = 'commonjs2';
Установите свой обычный devtool
config.devtool = 'source-map';
Встроенные карты источника не будут работатьв Screeps.
Установка внешних
config.externals = {
'main.js.map': 'main.js.map',
};
Это так, что мы можем написать require('main.js.map')
в нашем коде для загрузки файла карты источникаво время выполнения Screeps и чтобы Webpack оставил его в покое.
В tsconfig.json установите config.compilerOptions.sourceMap
в true
.
ЗагрузитьВаш код на сервер Screeps:
- Загрузите файл комплекта
main.js
как обычно. - Загрузите исходный файл карты.Назовите это
main.js.map.js
.Последний .js
важен - игра Screeps обрежет его, оставив желаемое main.js.map
.
Самостоятельно проанализируйте вашу исходную карту во время выполнения!
yarn add source-map
/ npm -i source-map --save
. - Оставьте его в версии ^ 0.6.1.^ 0.7 (последний на данный момент) только асинхронный.Асинхронный код не работает в Screeps.
- Используйте его, чтобы создать ошибку сообщения трассировки стека вручную.Затем распечатайте его, используя
console.log()
. - Да, это стоимость внутриигрового процессора.Кэшируйте свои сообщения об ошибках, чтобы при возникновении новой ошибки вы анализировали ее только один раз, а не в каждом тике.
- Кроме того, карта источника не будет работать в режиме симуляции (хотелось бы, чтобы я знал это быстрее).
Оберните ваш код в маппер ошибок:
export const loop = () => {
errorMapper(tick)();
};
const tick = () => { /* your regular code for current tick */};
Удачной отладки нормальным способом!
Собственно, это мой error-mapper.ts:
import { escape } from 'lodash';
import { MappedPosition, SourceMapConsumer } from 'source-map'; // leave it at version ^0.6.1. ^0.7 is async only.
export default function errorMapper(tick: () => void): () => void {
return () => {
try {
tick();
} catch (error) {
if (error instanceof Error) {
const isSimulation: boolean = ('sim' in Game.rooms);
if (isSimulation) {
printOriginalError(error);
} else {
printStackTrace(error);
}
} else {
throw error;
}
}
};
}
// tslint:disable-next-line: no-var-requires
const consumer: SourceMapConsumer = new SourceMapConsumer(require('main.js.map')); // High CPU usage!
const cache: { [key: string]: string } = {};
function getSourceMapStackTrace(error: Error | string): string {
const originalStackTrace: string = error instanceof Error ? error.stack as string : error;
if (cache[originalStackTrace]) {
return cache[originalStackTrace];
}
const re = /^\s+at\s+(.+?\s+)?\(?([0-z._\-\\\/]+):(\d+):(\d+)\)?$/gm;
let match: RegExpExecArray | null;
let outputStackTrace: string = error.toString();
// tslint:disable-next-line:no-conditional-assignment
while ((match = re.exec(originalStackTrace)) !== null) {
const nameFromOriginalStackTrace: string = match[1];
const isStackTraceLineControlledByMe: boolean = match[2] === 'main';
const lineFromOriginalStackTrace: number = parseInt(match[3], 10);
const columnFromOriginalStackTrace: number = parseInt(match[4], 10);
if (!isStackTraceLineControlledByMe) {
break;
}
const { name, source, line, column }: MappedPosition = consumer.originalPositionFor({
column: columnFromOriginalStackTrace,
line: lineFromOriginalStackTrace,
});
if (!line) {
break;
}
const finalName = (name) ? name : (nameFromOriginalStackTrace) ? nameFromOriginalStackTrace : '';
outputStackTrace += stripWebpackFromStackTrace(
`\n at ${finalName}(${source}:${line}:${column})`,
);
}
cache[originalStackTrace] = outputStackTrace;
return outputStackTrace;
}
function printOriginalError(error: Error) {
const message = `Source maps don't work in the Simulation mode.`;
console.log(`<span style="color: tomato">${message}\n${escape(error.stack)}</span>`);
}
function printStackTrace(error: Error) {
const errorMessage = escape(getSourceMapStackTrace(error));
console.log(`<span style="color: tomato">${errorMessage}</span>`);
Game.notify(errorMessage);
}
function stripWebpackFromStackTrace(text: string): string {
return text.replace('webpack:///', '');
}
Кроме того, благодаря screeps-typcript-starter , потому что это помогломне многое понять, source-map
использование библиотеки в сценарии использования Screeps.Мне, вероятно, не пришлось бы тратить слишком много на эту проблему, если бы я не хотел писать и понимать весь мой код Screeps и придерживаться Webpack.:)