Screeps: Как настроить исходную карту, используя TypeScript и Webpack? - PullRequest
0 голосов
/ 26 июня 2018

Я пытаюсь установить свой новый проект Screeps (игра) с нуля, используя TypeScript (^ 2.9.2) и Webpack (^ 4.12.1).Как правильно настроить исходные карты?Что я сделал:

  1. Установите "sourceMap": true, в tsconfig.json
  2. Установите devtool: 'inline-source-map', в webpack.config.js.Я полагаю, что для Screeps необходим встроенный файл?
  3. Установите loader: "source-map-loader", для test: /\.ts$/, enforce: 'pre', в конфигурации веб-пакета, чтобы не потерять исходные карты TS.

В моем main.ts, что вернотеперь просто console.log(foo); приводит к:

ReferenceError: foo is not defined
    at Object../src/main.ts:98:13
    at __webpack_require__:20:30
    at eval:84:18
    at main:87:10
    at eval:105:4
    at Object.<anonymous>:2:143759
    at Object.r.run:2:144268```

Это имеет место в клиентской консоли Screeps.В Firefox я вижу только foo is not defined без какой-либо более конкретной информации.

Есть ли способ получить /src/main.ts:1:13 (правильный номер строки) где-нибудь в трассировке стека?Это выглядит так, как будто не было бы никакой исходной карты, но в основной сборке main.js она есть:

//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vc3JjL21haW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0RBQTBDLGdDQUFnQztBQUMxRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdFQUF3RCxrQkFBa0I7QUFDMUU7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQXlDLGlDQUFpQztBQUMxRSx3SEFBZ0gsbUJBQW1CLEVBQUU7QUFDckk7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUNsRkEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyIsImZpbGUiOiJtYWluLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9zcmMvbWFpbi50c1wiKTtcbiIsImNvbnNvbGUubG9nKCdJdCB3b3JrcycpO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==

1 Ответ

0 голосов
/ 29 июля 2018

Фу, мне удалось заставить его работать.Вот что нужно сделать:

  1. В конфигурации веб-пакета:

    • Установить цель для '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 оставил его в покое.

  2. В tsconfig.json установите config.compilerOptions.sourceMap в true.

  3. ЗагрузитьВаш код на сервер Screeps:

    • Загрузите файл комплекта main.js как обычно.
    • Загрузите исходный файл карты.Назовите это main.js.map.js.Последний .js важен - игра Screeps обрежет его, оставив желаемое main.js.map.
  4. Самостоятельно проанализируйте вашу исходную карту во время выполнения!

    • yarn add source-map / npm -i source-map --save.
    • Оставьте его в версии ^ 0.6.1.^ 0.7 (последний на данный момент) только асинхронный.Асинхронный код не работает в Screeps.
    • Используйте его, чтобы создать ошибку сообщения трассировки стека вручную.Затем распечатайте его, используя console.log().
    • Да, это стоимость внутриигрового процессора.Кэшируйте свои сообщения об ошибках, чтобы при возникновении новой ошибки вы анализировали ее только один раз, а не в каждом тике.
    • Кроме того, карта источника не будет работать в режиме симуляции (хотелось бы, чтобы я знал это быстрее).
  5. Оберните ваш код в маппер ошибок:

    export const loop = () => {
      errorMapper(tick)();
    };
    
    const tick = () => { /* your regular code for current tick */};
    
  6. Удачной отладки нормальным способом!


Собственно, это мой 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.:)

...