feat(compiler-sfc): gen source map for style and script block (#497)
This commit is contained in:
parent
dcfac07431
commit
65118327ff
@ -4,6 +4,19 @@ import { mockWarn } from '@vue/runtime-test'
|
||||
describe('compiler:sfc', () => {
|
||||
mockWarn()
|
||||
|
||||
describe('source map', () => {
|
||||
test('style block', () => {
|
||||
const style = parse(`<style>\n.color {\n color: red;\n }\n</style>\n`)
|
||||
.styles[0]
|
||||
expect(style.map).not.toBeUndefined()
|
||||
})
|
||||
|
||||
test('script block', () => {
|
||||
const script = parse(`<script>\nconsole.log(1)\n }\n</script>\n`).script
|
||||
expect(script!.map).not.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
test('should ignore nodes with no content', () => {
|
||||
expect(parse(`<template/>`).template).toBe(null)
|
||||
expect(parse(`<script/>`).script).toBe(null)
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
ElementNode,
|
||||
SourceLocation
|
||||
} from '@vue/compiler-core'
|
||||
import { RawSourceMap } from 'source-map'
|
||||
import { RawSourceMap, SourceMapGenerator } from 'source-map'
|
||||
import LRUCache from 'lru-cache'
|
||||
import { generateCodeFrame } from '@vue/shared'
|
||||
|
||||
@ -14,6 +14,7 @@ export interface SFCParseOptions {
|
||||
needMap?: boolean
|
||||
filename?: string
|
||||
sourceRoot?: string
|
||||
pad?: 'line' | 'space'
|
||||
}
|
||||
|
||||
export interface SFCBlock {
|
||||
@ -56,7 +57,8 @@ export function parse(
|
||||
{
|
||||
needMap = true,
|
||||
filename = 'component.vue',
|
||||
sourceRoot = ''
|
||||
sourceRoot = '',
|
||||
pad = 'line'
|
||||
}: SFCParseOptions = {}
|
||||
): SFCDescriptor {
|
||||
const sourceKey = source + needMap + filename + sourceRoot
|
||||
@ -109,7 +111,28 @@ export function parse(
|
||||
})
|
||||
|
||||
if (needMap) {
|
||||
// TODO source map
|
||||
if (sfc.script && !sfc.script.src) {
|
||||
sfc.script.map = generateSourceMap(
|
||||
filename,
|
||||
source,
|
||||
sfc.script.content,
|
||||
sourceRoot,
|
||||
pad
|
||||
)
|
||||
}
|
||||
if (sfc.styles) {
|
||||
sfc.styles.forEach(style => {
|
||||
if (!style.src) {
|
||||
style.map = generateSourceMap(
|
||||
filename,
|
||||
source,
|
||||
style.content,
|
||||
sourceRoot,
|
||||
pad
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
sourceToSFC.set(sourceKey, sfc)
|
||||
|
||||
@ -164,3 +187,44 @@ function createBlock(node: ElementNode): SFCBlock {
|
||||
})
|
||||
return block
|
||||
}
|
||||
|
||||
const splitRE = /\r?\n/g
|
||||
const emptyRE = /^(?:\/\/)?\s*$/
|
||||
|
||||
function generateSourceMap(
|
||||
filename: string,
|
||||
source: string,
|
||||
generated: string,
|
||||
sourceRoot: string,
|
||||
pad?: 'line' | 'space'
|
||||
): RawSourceMap {
|
||||
const map = new SourceMapGenerator({
|
||||
file: filename.replace(/\\/g, '/'),
|
||||
sourceRoot: sourceRoot.replace(/\\/g, '/')
|
||||
})
|
||||
let offset = 0
|
||||
if (!pad) {
|
||||
offset =
|
||||
source
|
||||
.split(generated)
|
||||
.shift()!
|
||||
.split(splitRE).length - 1
|
||||
}
|
||||
map.setSourceContent(filename, source)
|
||||
generated.split(splitRE).forEach((line, index) => {
|
||||
if (!emptyRE.test(line)) {
|
||||
map.addMapping({
|
||||
source: filename,
|
||||
original: {
|
||||
line: index + 1 + offset,
|
||||
column: 0
|
||||
},
|
||||
generated: {
|
||||
line: index + 1,
|
||||
column: 0
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return JSON.parse(map.toString())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user