Skip to content

Commit 0680955

Browse files
committed
support source map in bundle renderer
1 parent eb07198 commit 0680955

File tree

6 files changed

+65
-6
lines changed

6 files changed

+65
-6
lines changed

build/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ const builds = {
8484
entry: path.resolve(__dirname, '../src/entries/web-server-renderer.js'),
8585
dest: path.resolve(__dirname, '../packages/vue-server-renderer/build.js'),
8686
format: 'cjs',
87-
external: ['stream', 'module', 'vm', 'he', 'de-indent']
87+
external: ['he', 'de-indent', 'source-map']
8888
},
8989
// Weex runtime factory
9090
'weex-factory': {

flow/modules.js

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ declare module 'source-map' {
99
addMapping(mapping: Object): void;
1010
toString(): string;
1111
}
12+
declare class SourceMapConsumer {
13+
originalPositionFor(position: { line: number; column: number; }): {
14+
source: ?string;
15+
line: ?number;
16+
column: ?number;
17+
};
18+
}
1219
}
1320

1421
declare module 'lru-cache' {

src/core/components/keep-alive.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { callHook } from 'core/instance/lifecycle'
44
import { getFirstComponentChild } from 'core/vdom/helpers/index'
55

6-
const patternTypes = [String, RegExp]
6+
const patternTypes: Array<Function> = [String, RegExp]
77

88
function getComponentName (opts: ?VNodeComponentOptions): ?string {
99
return opts && (opts.Ctor.options.name || opts.tag)

src/platforms/web/server/modules/dom-props.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default function renderDOMProps (node: VNodeWithData): string {
2525
if (key === 'innerHTML') {
2626
setText(node, props[key], true)
2727
} else if (key === 'textContent') {
28-
setText(node, props[key])
28+
setText(node, props[key], false)
2929
} else {
3030
const attr = propsToAttrMap[key] || key.toLowerCase()
3131
if (isRenderableAttr(attr) &&

src/server/create-bundle-renderer.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* @flow */
22

33
import runInVm from './run-in-vm'
4-
import { PassThrough } from 'stream'
54
import type { Renderer, RenderOptions } from './create-renderer'
5+
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
6+
7+
const PassThrough = require('stream').PassThrough
68

79
const INVALID_MSG =
810
'Invalid server-rendering bundle format. Should be a string ' +
@@ -24,16 +26,18 @@ type RenderBundle = string | {
2426
export function createBundleRendererCreator (createRenderer: () => Renderer) {
2527
return (bundle: RenderBundle, rendererOptions?: RenderOptions) => {
2628
const renderer = createRenderer(rendererOptions)
27-
let files, entry
29+
let files, entry, maps
2830
if (typeof bundle === 'object') {
2931
entry = bundle.entry
3032
files = bundle.files
33+
maps = createSourceMapConsumers(bundle.maps)
3134
if (typeof entry !== 'string' || typeof files !== 'object') {
3235
throw new Error(INVALID_MSG)
3336
}
3437
} else if (typeof bundle === 'string') {
3538
entry = '__vue_ssr_bundle__'
3639
files = { '__vue_ssr_bundle__': bundle }
40+
maps = {}
3741
} else {
3842
throw new Error(INVALID_MSG)
3943
}
@@ -45,18 +49,23 @@ export function createBundleRendererCreator (createRenderer: () => Renderer) {
4549
}
4650
runInVm(entry, files, context).then(app => {
4751
renderer.renderToString(app, cb)
48-
}).catch(cb)
52+
}).catch(err => {
53+
rewriteErrorTrace(err, maps)
54+
cb(err)
55+
})
4956
},
5057
renderToStream: (context?: Object) => {
5158
const res = new PassThrough()
5259
runInVm(entry, files, context).then(app => {
5360
const renderStream = renderer.renderToStream(app)
5461
renderStream.on('error', err => {
62+
rewriteErrorTrace(err, maps)
5563
res.emit('error', err)
5664
})
5765
renderStream.pipe(res)
5866
}).catch(err => {
5967
process.nextTick(() => {
68+
rewriteErrorTrace(err, maps)
6069
res.emit('error', err)
6170
})
6271
})

src/server/source-map-support.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* @flow */
2+
3+
const SourceMapConsumer = require('source-map').SourceMapConsumer
4+
5+
const filenameRE = /\(([^)]+\.js):(\d+):(\d+)\)$/
6+
7+
export function createSourceMapConsumers (rawMaps: Object) {
8+
const maps = {}
9+
Object.keys(rawMaps).forEach(file => {
10+
maps[file] = new SourceMapConsumer(rawMaps[file])
11+
})
12+
return maps
13+
}
14+
15+
export function rewriteErrorTrace (e: Error, mapConsumers: {
16+
[key: string]: SourceMapConsumer
17+
}) {
18+
e.stack = e.stack.split('\n').map(line => {
19+
return rewriteTraceLine(line, mapConsumers)
20+
}).join('\n')
21+
}
22+
23+
function rewriteTraceLine (trace: string, mapConsumers: {
24+
[key: string]: SourceMapConsumer
25+
}) {
26+
const m = trace.match(filenameRE)
27+
const map = m && mapConsumers[m[1]]
28+
if (m != null && map) {
29+
const originalPosition = map.originalPositionFor({
30+
line: Number(m[2]),
31+
column: Number(m[3])
32+
})
33+
if (originalPosition.source != null) {
34+
const { source, line, column } = originalPosition
35+
const mappedPosition = `(${source.replace(/^webpack:\/\/\//, '')}:${line}:${column})`
36+
return trace.replace(filenameRE, mappedPosition)
37+
} else {
38+
return trace
39+
}
40+
} else {
41+
return trace
42+
}
43+
}

0 commit comments

Comments
 (0)