diff --git a/package.json b/package.json index 77c5fb11c..b372af4b9 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", - "semver": "^7.3.4" + "semver": "^7.3.4", + "source-map": "^0.7.3" }, "devDependencies": { "@types/micromatch": "^4.0.0", diff --git a/src/index.ts b/src/index.ts index c225dc04c..3bb0226e7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,10 @@ import * as crypto from 'crypto'; import * as path from 'path'; +import { + RawSourceMap, + SourceMapConsumer, + SourceMapGenerator, +} from 'source-map'; import type * as typescript from 'typescript'; import type * as webpack from 'webpack'; @@ -31,7 +36,11 @@ const loaderOptionsCache: LoaderOptionsCache = {}; /** * The entry point for ts-loader */ -function loader(this: webpack.LoaderContext, contents: string) { +function loader( + this: webpack.LoaderContext, + contents: string, + map?: Record +) { this.cacheable && this.cacheable(); const callback = this.async(); const options = getLoaderOptions(this); @@ -43,14 +52,15 @@ function loader(this: webpack.LoaderContext, contents: string) { } const instance = instanceOrError.instance!; buildSolutionReferences(instance, this); - successLoader(this, contents, callback, instance); + successLoader(this, contents, callback, instance, map); } function successLoader( loaderContext: webpack.LoaderContext, contents: string, callback: ReturnType['async']>, - instance: TSInstance + instance: TSInstance, + map?: Record ) { initializeInstance(loaderContext, instance); reportTranspileErrors(instance, loaderContext); @@ -86,11 +96,12 @@ function successLoader( loaderContext, fileVersion, callback, - instance + instance, + map ); } -function makeSourceMapAndFinish( +async function makeSourceMapAndFinish( sourceMapText: string | undefined, outputText: string | undefined, filePath: string, @@ -98,7 +109,8 @@ function makeSourceMapAndFinish( loaderContext: webpack.LoaderContext, fileVersion: number, callback: ReturnType['async']>, - instance: TSInstance + instance: TSInstance, + map?: Record ) { if (outputText === null || outputText === undefined) { setModuleMeta(loaderContext, instance, fileVersion); @@ -129,8 +141,10 @@ function makeSourceMapAndFinish( loaderContext ); + const mappedSourceMap = await mapSourceMap(sourceMap, loaderContext, map); + setModuleMeta(loaderContext, instance, fileVersion); - callback(null, output, sourceMap); + callback(null, output, mappedSourceMap); } function setModuleMeta( @@ -649,6 +663,23 @@ function makeSourceMap( }; } +async function mapSourceMap( + sourceMap: RawSourceMap, + loaderContext: webpack.LoaderContext, + map?: Record +) { + if (sourceMap !== undefined && map !== undefined) { + const inMap = map as RawSourceMap; + inMap.file = loaderContext.remainingRequest; + const sm1 = await new SourceMapConsumer(inMap); + const sm2 = await new SourceMapConsumer(sourceMap); + const generator = SourceMapGenerator.fromSourceMap(sm2); + generator.applySourceMap(sm1); + return generator.toJSON(); + } + return sourceMap; +} + export = loader; /** diff --git a/src/instances.ts b/src/instances.ts index 3b509c29b..877b0b2cb 100644 --- a/src/instances.ts +++ b/src/instances.ts @@ -351,7 +351,7 @@ export function initializeInstance( } else if (typeof customerTransformers === 'string') { try { customerTransformers = require(customerTransformers); - } catch (err) { + } catch (err: any) { throw new Error( `Failed to load customTransformers from "${instance.loaderOptions.getCustomTransformers}": ${err.message}` );