Screeps:如何使用TypeScript和Webpack设置源地图?
我正在尝试使用TypeScript(^2.9.2)和Webpack(^4.12.1)从头开始设置新的Screeps(游戏)项目。如何正确设置源地图?我所做的:Screeps:如何使用TypeScript和Webpack设置源地图?,typescript,webpack,source-maps,screeps,Typescript,Webpack,Source Maps,Screeps,我正在尝试使用TypeScript(^2.9.2)和Webpack(^4.12.1)从头开始设置新的Screeps(游戏)项目。如何正确设置源地图?我所做的: 在tsconfig.json中设置“sourceMap”:true, 在webpack.config.js中设置devtool:“内联源代码映射”。我想内联是尖叫的必要条件 设置loader:test:/\.ts$/,的loader:,在网页包配置中强制执行:'pre',,以避免丢失ts源地图 在我的main.ts中,它现在只是conso
“sourceMap”:true,
devtool:“内联源代码映射”
。我想内联是尖叫的必要条件loader:test:/\.ts$/,
的loader:
,在网页包配置中强制执行:'pre',
,以避免丢失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```
唷,我成功了。以下是需要做的事情:
在网页包配置中:
- 将目标设置为“节点”
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
bundle文件
- 上传你的源地图文件。将其命名为
main.js.map.js
。最后一个.js
很重要-Screeps游戏会将其切断,留下所需的main.js.map
在运行时自己解析源映射
添加源映射
/npm-i源映射--保存
- 将其保留为版本^0.6.1^0.7(目前最新版本)仅为异步。异步代码在Screeps中不起作用
- 使用它手动生成stacktrace消息错误。然后使用
console.log()
打印它
- 是的,这需要游戏中的CPU。缓存错误消息,以便在遇到新错误时只解析一次,而不是每次都解析一次
- 另外,源映射在模拟模式下也不起作用(我希望知道得更快)
围绕错误映射器包装您的代码:
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:///', '');
}
从'lodash'导入{escape};
从“源映射”导入{MappedPosition,SourceMapConsumer};//将其保留为版本^0.6.1^0.7只是异步的。
导出默认函数errorMapper(勾选:()=>void):()=>void{
return()=>{
试一试{
勾选();
}捕获(错误){
if(错误实例of error){
const-isSimulation:boolean=('sim'在Game.rooms中);
如果(模拟){
打印原件错误(错误);
}否则{
printStackTrace(错误);
}
}否则{
投掷误差;
}
}
};
}
//tslint:禁用下一行:无需var
const consumer:SourceMapConsumer=新的SourceMapConsumer(require('main.js.map'));//高CPU使用率!
常量缓存:{[key:string]:string}={};
函数getSourceMapStackTrace(错误:错误|字符串):字符串{
const originalStackTrace:string=error instanceof error?error.stack as string:error;
if(缓存[originalStackTrace]){
返回缓存[originalStackTrace];
}
常量re=/^\s+at\s+(.+?\s+)\(([0-z.\u\-\\/]+):(\ d+):(\d+)?$/gm;
let match:RegExpExecArray | null;
let outputStackTrace:string=error.toString();
//tslint:禁用下一行:无条件赋值
while((match=re.exec(originalStackTrace))!==null){
const nameFromOriginalStackTrace:string=match[1];
const IsStackTraceLineControl ByMe:boolean=匹配[2]=='main';
const lineFromOriginalStackTrace:number=parseInt(匹配[3],10);
const columnFrominalsTackTrace:number=parseInt(匹配[4],10);
如果(!IsStackTraceLineControl ByMe){
打破
}
常量{name,source,line,column}:MappedPosition=consumer.originalPositionFor({
column:ColumnFromInitialStackTrace,
line:lineFromOriginalStackTrace,
});
如果(!行){
打破
}
const finalName=(name)?name:(nameFromOriginalStackTrace)?nameFromOriginalStackTrace:“”;
outputStackTrace+=StripWebPackageFromStackTrace(
`\n位于${finalName}(${source}:${line}:${column})`,
);
}
cache[originalStackTrace]=outputStackTrace;
返回outputStackTrace;
}
函数printOriginalError(错误:error){
const message=`源映射在模拟模式下不工作。`;
log(`${message}\n${escape(error.stack)}`);
}
函数printStackTrace(错误:error){
const errorMessage=escape(getSourceMapStackTrace(错误));
log(`${errorMessage}`);
通知(错误消息);
}
函数stripWebpackFromStackTrace(文本:string):string{
返回文本。替换('webpack://','';
}
另外,感谢,因为它帮助我了解了Screeps用例中源代码映射库的用法。如果我不想编写和理解我所有的尖叫代码并坚持使用Webpack,我可能不需要在这个问题上花费太多 嘿,干得好!你知道为什么源地图不能在模拟模式下工作吗?我仍在进行原型设计,还没有准备好在尖叫声上花钱。
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:///', '');
}