11import * as webpack from 'webpack'
22import qs from 'querystring'
3+ import chalk from 'chalk'
34import loaderUtils from 'loader-utils'
45import { 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'
108
119// Loader that compiles raw template into JavaScript functions.
1210// This is injected by the global pitcher (../pitch) for template
1311// selection requests initiated from vue files.
14- const TemplateLoader : webpack . loader . Loader = function ( source ) {
12+ const TemplateLoader : webpack . loader . Loader = function ( source , inMap ) {
1513 source = String ( source )
1614 const loaderContext = this
17- const query = qs . parse ( this . resourceQuery . slice ( 1 ) )
1815
1916 // although this is not the main vue-loader, we can get access to the same
2017 // vue-loader options because we've set an ident in the plugin and used that
2118 // ident to create the request for this loader in the pitcher.
2219 const options = ( loaderUtils . getOptions ( loaderContext ) ||
2320 { } ) as VueLoaderOptions
24- const { id } = query
21+
2522 // const isServer = loaderContext.target === 'node'
2623 // 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
2727
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 ( {
3529 source,
3630 filename : this . resourcePath ,
3731 compiler : options . compiler ,
38- compilerOptions,
32+ compilerOptions : options . compilerOptions ,
3933 transformAssetUrls : options . transformAssetUrls || true
40- }
41-
42- const compiled = compileTemplate ( finalOptions )
34+ } )
4335
4436 // tips
4537 if ( compiled . tips . length ) {
@@ -50,17 +42,24 @@ const TemplateLoader: webpack.loader.Loader = function(source) {
5042
5143 // errors
5244 if ( compiled . errors && compiled . errors . length ) {
45+ const lineOffset = inMap ? getLineOffset ( inMap ) : 0
5346 compiled . errors . forEach ( err => {
5447 if ( typeof err === 'string' ) {
5548 loaderContext . emitError ( err )
5649 } else {
5750 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 (
6058 source as string ,
6159 err . loc . start . offset ,
62- err . loc . end . offset
63- ) } `
60+ err . loc . end . offset ,
61+ lineOffset
62+ ) ) } \n`
6463 }
6564 loaderContext . emitError ( err )
6665 }
@@ -71,4 +70,13 @@ const TemplateLoader: webpack.loader.Loader = function(source) {
7170 loaderContext . callback ( null , code , map as any )
7271}
7372
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+
7482module . exports = TemplateLoader
0 commit comments