1
1
import * as webpack from 'webpack'
2
2
import qs from 'querystring'
3
+ import chalk from 'chalk'
3
4
import loaderUtils from 'loader-utils'
4
5
import { VueLoaderOptions } from './'
5
- import {
6
- compileTemplate ,
7
- TemplateCompileOptions ,
8
- generateCodeFrame
9
- } from '@vue/compiler-sfc'
6
+ import { SourceMapConsumer , RawSourceMap } from 'source-map'
7
+ import { compileTemplate , generateCodeFrame } from '@vue/compiler-sfc'
10
8
11
9
// Loader that compiles raw template into JavaScript functions.
12
10
// This is injected by the global pitcher (../pitch) for template
13
11
// selection requests initiated from vue files.
14
- const TemplateLoader : webpack . loader . Loader = function ( source ) {
12
+ const TemplateLoader : webpack . loader . Loader = function ( source , inMap ) {
15
13
source = String ( source )
16
14
const loaderContext = this
17
- const query = qs . parse ( this . resourceQuery . slice ( 1 ) )
18
15
19
16
// although this is not the main vue-loader, we can get access to the same
20
17
// vue-loader options because we've set an ident in the plugin and used that
21
18
// ident to create the request for this loader in the pitcher.
22
19
const options = ( loaderUtils . getOptions ( loaderContext ) ||
23
20
{ } ) as VueLoaderOptions
24
- const { id } = query
21
+
25
22
// const isServer = loaderContext.target === 'node'
26
23
// const isProduction = options.productionMode || loaderContext.minimize || process.env.NODE_ENV === 'production'
24
+ const query = qs . parse ( this . resourceQuery . slice ( 1 ) )
25
+ const scopedId = query . scoped ? `data-v-${ query . id } ` : null
26
+ scopedId // TODO this is for SSR
27
27
28
- const compilerOptions = Object . assign ( { } , options . compilerOptions , {
29
- // TODO line offset
30
- scopeId : query . scoped ? `data-v-${ id } ` : null
31
- } )
32
-
33
- // for vue-component-compiler
34
- const finalOptions : TemplateCompileOptions = {
28
+ const compiled = compileTemplate ( {
35
29
source,
36
30
filename : this . resourcePath ,
37
31
compiler : options . compiler ,
38
- compilerOptions,
32
+ compilerOptions : options . compilerOptions ,
39
33
transformAssetUrls : options . transformAssetUrls || true
40
- }
41
-
42
- const compiled = compileTemplate ( finalOptions )
34
+ } )
43
35
44
36
// tips
45
37
if ( compiled . tips . length ) {
@@ -50,17 +42,24 @@ const TemplateLoader: webpack.loader.Loader = function(source) {
50
42
51
43
// errors
52
44
if ( compiled . errors && compiled . errors . length ) {
45
+ const lineOffset = inMap ? getLineOffset ( inMap ) : 0
53
46
compiled . errors . forEach ( err => {
54
47
if ( typeof err === 'string' ) {
55
48
loaderContext . emitError ( err )
56
49
} else {
57
50
if ( err . loc ) {
58
- err . message = `\n${ err . message } \n\n${
59
- generateCodeFrame (
51
+ const filePath = chalk . blueBright ( `${
52
+ loaderContext . resourcePath
53
+ } :${ err . loc . start . line } :${ err . loc . start . column } `)
54
+ err . message = `\n${ filePath } \n${
55
+ chalk . red ( err . message . replace ( / \s + \( \d + : \d + \) / , '' ) )
56
+ } \n${
57
+ chalk . yellow ( generateCodeFrame (
60
58
source as string ,
61
59
err . loc . start . offset ,
62
- err . loc . end . offset
63
- ) } `
60
+ err . loc . end . offset ,
61
+ lineOffset
62
+ ) ) } \n`
64
63
}
65
64
loaderContext . emitError ( err )
66
65
}
@@ -71,4 +70,13 @@ const TemplateLoader: webpack.loader.Loader = function(source) {
71
70
loaderContext . callback ( null , code , map as any )
72
71
}
73
72
73
+ function getLineOffset ( map : RawSourceMap ) : number {
74
+ const consumer = new SourceMapConsumer ( map )
75
+ let offset = 0
76
+ consumer . eachMapping ( map => {
77
+ offset = map . originalLine - map . generatedLine
78
+ } )
79
+ return offset
80
+ }
81
+
74
82
module . exports = TemplateLoader
0 commit comments