如何创build连接文件的源映射

我想连接一个单一types的一堆不同的文件到一个大文件。 例如,很多javascript文件放到一个大文件中,很多css文件放在一个文件中等等。我想创build一个文件pre-concatenation的sourcemap,但是我不知道从哪里开始。 我在Node工作,但我也开放在其他环境中的解决scheme。

我知道有些工具可以做到这一点,但是他们似乎是按照语言(uglifyjs,cssmin或者其他所谓的语言)的语言,但是我想要一个不是特定于语言的工具。

另外,我想定义文件是如何绑定的。 例如,在JavaScript中,我想给每个文件自己封闭一个IIFE。 如:

(function () { // File }()); 

我也可以想到其他包装我想实现不同的文件。

这是我现在看到的选项。 但是,我不知道哪一个是最好的,或者如何开始其中的任何一个。

  1. find一个这样做的模块(我在Node.js环境中工作)
  2. 用Mozilla的源图模块创build一个algorithm。 为此,我也看到一些选项。
    1. 只将每一行映射到新的行位置
    2. 将每个字符映射到新位置
    3. 将每个单词映射到新的位置(这个选项似乎超出了范围)
  3. 不要担心源地图

你们对这些select有什么看法? 我已经尝试了选项2.1和2.2,但对于级联algorithm来说,解决scheme似乎太复杂了,并且在Google Chrome浏览器工具中没有完美实现。

我实现了代码没有任何依赖这样的:

 export interface SourceMap { version: number; // always 3 file?: string; sourceRoot?: string; sources: string[]; sourcesContent?: string[]; names?: string[]; mappings: string | Buffer; } const emptySourceMap: SourceMap = { version: 3, sources: [], mappings: new Buffer(0) } var charToInteger = new Buffer(256); var integerToChar = new Buffer(64); charToInteger.fill(255); 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('').forEach((char, i) => { charToInteger[char.charCodeAt(0)] = i; integerToChar[i] = char.charCodeAt(0); }); class DynamicBuffer { buffer: Buffer; size: number; constructor() { this.buffer = new Buffer(512); this.size = 0; } ensureCapacity(capacity: number) { if (this.buffer.length >= capacity) return; let oldBuffer = this.buffer; this.buffer = new Buffer(Math.max(oldBuffer.length * 2, capacity)); oldBuffer.copy(this.buffer); } addByte(b: number) { this.ensureCapacity(this.size + 1); this.buffer[this.size++] = b; } addVLQ(num: number) { var clamped: number; if (num < 0) { num = (-num << 1) | 1; } else { num <<= 1; } do { clamped = num & 31; num >>= 5; if (num > 0) { clamped |= 32; } this.addByte(integerToChar[clamped]); } while (num > 0); } addString(s: string) { let l = Buffer.byteLength(s); this.ensureCapacity(this.size + l); this.buffer.write(s, this.size); this.size += l; } addBuffer(b: Buffer) { this.ensureCapacity(this.size + b.length); b.copy(this.buffer, this.size); this.size += b.length; } toBuffer(): Buffer { return this.buffer.slice(0, this.size); } } function countNL(b: Buffer): number { let res = 0; for (let i = 0; i < b.length; i++) { if (b[i] === 10) res++; } return res; } export class SourceMapBuilder { outputBuffer: DynamicBuffer; sources: string[]; mappings: DynamicBuffer; lastSourceIndex = 0; lastSourceLine = 0; lastSourceCol = 0; constructor() { this.outputBuffer = new DynamicBuffer(); this.mappings = new DynamicBuffer(); this.sources = []; } addLine(text: string) { this.outputBuffer.addString(text); this.outputBuffer.addByte(10); this.mappings.addByte(59); // ; } addSource(content: Buffer, sourceMap?: SourceMap) { if (sourceMap == null) sourceMap = emptySourceMap; this.outputBuffer.addBuffer(content); let sourceLines = countNL(content); if (content.length > 0 && content[content.length - 1] !== 10) { sourceLines++; this.outputBuffer.addByte(10); } let sourceRemap = []; sourceMap.sources.forEach((v) => { let pos = this.sources.indexOf(v); if (pos < 0) { pos = this.sources.length; this.sources.push(v); } sourceRemap.push(pos); }); let lastOutputCol = 0; let inputMappings = (typeof sourceMap.mappings === "string") ? new Buffer(<string>sourceMap.mappings) : <Buffer>sourceMap.mappings; let outputLine = 0; let ip = 0; let inOutputCol = 0; let inSourceIndex = 0; let inSourceLine = 0; let inSourceCol = 0; let shift = 0; let value = 0; let valpos = 0; const commit = () => { if (valpos === 0) return; this.mappings.addVLQ(inOutputCol - lastOutputCol); lastOutputCol = inOutputCol; if (valpos === 1) { valpos = 0; return; } let outSourceIndex = sourceRemap[inSourceIndex]; this.mappings.addVLQ(outSourceIndex - this.lastSourceIndex); this.lastSourceIndex = outSourceIndex; this.mappings.addVLQ(inSourceLine - this.lastSourceLine); this.lastSourceLine = inSourceLine; this.mappings.addVLQ(inSourceCol - this.lastSourceCol); this.lastSourceCol = inSourceCol; valpos = 0; } while (ip < inputMappings.length) { let b = inputMappings[ip++]; if (b === 59) { // ; commit(); this.mappings.addByte(59); inOutputCol = 0; lastOutputCol = 0; outputLine++; } else if (b === 44) { // , commit(); this.mappings.addByte(44); } else { b = charToInteger[b]; if (b === 255) throw new Error("Invalid sourceMap"); value += (b & 31) << shift; if (b & 32) { shift += 5; } else { let shouldNegate = value & 1; value >>= 1; if (shouldNegate) value = -value; switch (valpos) { case 0: inOutputCol += value; break; case 1: inSourceIndex += value; break; case 2: inSourceLine += value; break; case 3: inSourceCol += value; break; } valpos++; value = shift = 0; } } } commit(); while (outputLine < sourceLines) { this.mappings.addByte(59); outputLine++; } } toContent(): Buffer { return this.outputBuffer.toBuffer(); } toSourceMap(sourceRoot?: string): Buffer { return new Buffer(JSON.stringify({ version: 3, sourceRoot, sources: this.sources, mappings: this.mappings.toBuffer().toString() })); } } 

我首先从这个规范中实现了“索引图”,只是发现它不被任何浏览器支持。

另一个可能有用的项目是魔术string 。

Interesting Posts