Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.

Commit bfca1be

Browse files
committed
fix(sourcemaps): webpack .ts sourcemaps
1 parent 922404a commit bfca1be

File tree

9 files changed

+315
-161
lines changed

9 files changed

+315
-161
lines changed

config/webpack.config.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
var path = require('path');
22
var webpack = require('webpack');
33

4-
5-
6-
7-
// for prod builds, we have already done AoT and AoT writes to disk
8-
// so read the JS file from disk
9-
// for dev buids, we actually want to pass in .ts files since we
10-
// don't have .js files on disk, they're exclusively in memory
11-
124
function getEntryPoint() {
135
if (process.env.IONIC_ENV === 'prod') {
146
return '{{TMP}}/app/main.prod.js';
@@ -21,6 +13,7 @@ function getPlugins() {
2113
return [
2214
// This helps ensure the builds are consistent if source hasn't changed:
2315
new webpack.optimize.OccurrenceOrderPlugin(),
16+
2417
// Try to dedupe duplicated modules, if any:
2518
// Add this back in when Angular fixes the issue: https://github.com/angular/angular-cli/issues/1587
2619
//new DedupePlugin()
@@ -29,6 +22,20 @@ function getPlugins() {
2922
return [];
3023
}
3124

25+
function getSourcemapLoader() {
26+
if (process.env.IONIC_ENV === 'prod') {
27+
// TODO figure out the disk loader, it's not working yet
28+
return [];
29+
}
30+
31+
return [
32+
{
33+
test: /\.js$/,
34+
loader: path.resolve(path.join(process.cwd(), 'node_modules', '@ionic', 'app-scripts', 'dist', 'loaders', 'typescript-sourcemap-loader-memory.js'))
35+
}
36+
];
37+
}
38+
3239
module.exports = {
3340
entry: getEntryPoint(),
3441
output: {
@@ -47,7 +54,7 @@ module.exports = {
4754
test: /\.json$/,
4855
loader: 'json'
4956
}
50-
]
57+
].concat(getSourcemapLoader())
5158
},
5259

5360
plugins: getPlugins(),
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Logger } from '../util/logger';
2+
import { changeExtension, readFileAsync } from '../util/helpers';
3+
4+
module.exports = function typescriptSourcemapLoaderDisk(source: string, map: string) {
5+
this.cacheable();
6+
var callback = this.async();
7+
8+
if ( this.resourcePath.indexOf('node_modules') > -1) {
9+
// it's not a source file, so use the default
10+
callback(null, source, map);
11+
} else {
12+
// it's a src file
13+
loadBetterSourceMap(this.resourcePath, callback, source, map);
14+
}
15+
};
16+
17+
function loadBetterSourceMap(javascriptFilePath: string, callback: Function, originalSource: any, originalMap: any) {
18+
const sourceMapPath = javascriptFilePath + '.map';
19+
const tsFilePath = changeExtension(javascriptFilePath, '.ts');
20+
21+
let sourceMapContent: string = null;
22+
let typescriptFileContent: string = null;
23+
24+
const readSourceMapPromise = readFileAsync(sourceMapPath);
25+
readSourceMapPromise.then((content: string) => {
26+
sourceMapContent = content;
27+
});
28+
29+
const readTsFilePromise = readFileAsync(tsFilePath);
30+
readTsFilePromise.then((content: string) => {
31+
typescriptFileContent = content;
32+
});
33+
34+
let promises: Promise<any>[] = [];
35+
promises.push(readSourceMapPromise);
36+
promises.push(readTsFilePromise);
37+
38+
Promise.all(promises)
39+
.then(() => {
40+
if (!sourceMapContent || !sourceMapContent.length) {
41+
throw new Error('Failed to read sourcemap file');
42+
} else if (!typescriptFileContent || !typescriptFileContent.length) {
43+
throw new Error('Failed to read typescript file');
44+
} else {
45+
return JSON.parse(sourceMapContent);
46+
}
47+
}).then((sourceMapObject: any) => {
48+
if (!sourceMapObject.sourcesContent || sourceMapObject.sourcesContent.length === 0) {
49+
Logger.debug(`loadBetterSourceMap: Assigning Typescript content to source map for ${javascriptFilePath}`);
50+
sourceMapObject.sourcesContent = [typescriptFileContent];
51+
}
52+
callback(null, originalSource, sourceMapObject);
53+
}).catch((err: Error) => {
54+
Logger.debug(`Failed to generate typescript sourcemaps for ${javascriptFilePath}: ${err.message}`);
55+
// just use the default
56+
callback(null, originalSource, originalMap);
57+
});
58+
59+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Logger } from '../util/logger';
2+
import { changeExtension, getContext, transformTmpPathToSrcPath} from '../util/helpers';
3+
4+
module.exports = function typescriptSourcemapLoaderMemory(source: string, map: string) {
5+
this.cacheable();
6+
var callback = this.async();
7+
const context = getContext();
8+
const transformedPath = transformTmpPathToSrcPath(this.resourcePath, context);
9+
const sourceMapPath = transformedPath + '.map';
10+
const sourceMapFile = context.fileCache.get(sourceMapPath);
11+
12+
// get the typescript source if needed
13+
let sourcesContent = source;
14+
const isSrcFile = transformedPath !== this.resourcePath;
15+
if (isSrcFile) {
16+
Logger.debug('typescriptSourcemapLoaderMemory: attempting to use .ts instead of .js for sourcemap');
17+
const modifiedPath = changeExtension(transformedPath, '.ts');
18+
const typescriptFileObject = context.fileCache.get(modifiedPath);
19+
if (typescriptFileObject) {
20+
Logger.debug('typescriptSourcemapLoaderMemory: found the .ts file in memory, using it');
21+
sourcesContent = typescriptFileObject.content;
22+
}
23+
}
24+
25+
if ( sourceMapFile ) {
26+
const sourceMapObject = JSON.parse(sourceMapFile.content);
27+
if (!sourceMapObject.sourcesContent || sourceMapObject.sourcesContent.length === 0) {
28+
sourceMapObject.sourcesContent = [sourcesContent];
29+
}
30+
callback(null, source, sourceMapObject);
31+
} else {
32+
callback(null, source, map);
33+
}
34+
};
35+

src/plugins/ion-compiler.ts

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import { changeExtension } from '../util/helpers';
12
import { BuildContext } from '../util/interfaces';
3+
import { Logger } from '../util/logger';
24
import { dirname, join, resolve } from 'path';
35
import * as pluginutils from 'rollup-pluginutils';
46

57

68
export function ionCompiler(context: BuildContext) {
79
const filter = pluginutils.createFilter(INCLUDE, EXCLUDE);
810

11+
912
return {
1013
name: 'ion-compiler',
1114

@@ -14,16 +17,27 @@ export function ionCompiler(context: BuildContext) {
1417
return null;
1518
}
1619

17-
if (context.tsFiles) {
18-
const file = context.tsFiles[sourcePath];
19-
if (!file || !file.output) {
20-
console.error(`unable to find ${sourcePath}`);
20+
const jsSourcePath = changeExtension(sourcePath, '.js');
21+
22+
if (context.fileCache) {
23+
const file = context.fileCache.get(jsSourcePath);
24+
const map = context.fileCache.get(jsSourcePath + '.map');
25+
if (!file || !file.content) {
26+
Logger.debug(`transform: unable to find ${jsSourcePath}`);
2127
return null;
2228
}
2329

30+
let mapContent: any = null;
31+
if (map.content) {
32+
try {
33+
mapContent = JSON.parse(map.content);
34+
} catch (ex) {
35+
}
36+
}
37+
2438
return {
25-
code: file.output,
26-
map: file.map
39+
code: file.content,
40+
map: mapContent
2741
};
2842
}
2943

@@ -35,10 +49,10 @@ export function ionCompiler(context: BuildContext) {
3549
},
3650

3751
load(sourcePath: string) {
38-
if (context.tsFiles) {
39-
const file = context.tsFiles[sourcePath];
40-
if (file && file.input) {
41-
return file.input;
52+
if (context.fileCache) {
53+
const file = context.fileCache.get(sourcePath);
54+
if (file && file.content) {
55+
return file.content;
4256
}
4357
}
4458

@@ -55,26 +69,27 @@ export function resolveId(importee: string, importer: string, context: BuildCont
5569
return null;
5670
}
5771

58-
if (context.tsFiles) {
59-
const importerFile = context.tsFiles[importer];
60-
if (importerFile && importerFile.output) {
72+
if (context.fileCache) {
73+
const importerFile = context.fileCache.get(importer);
74+
if (importerFile && importerFile.content) {
6175
const attemptedImporteeBasename = resolve(join(dirname(importer), importee));
6276
const attemptedImportee = attemptedImporteeBasename + '.ts';
63-
const importeeFile = context.tsFiles[attemptedImportee];
77+
const importeeFile = context.fileCache.get(attemptedImportee);
6478
if (importeeFile) {
79+
Logger.debug(`resolveId: found and resolving ${attemptedImportee}`);
6580
return attemptedImportee;
6681
} else {
6782
// rather than a file, the attempedImportee could be a directory
6883
// while via node resolve pattern auto resolves to index file
6984
const attemptedImporteeIndex = resolve(join(attemptedImporteeBasename, 'index.ts'));
70-
const importeeIndexFile = context.tsFiles[attemptedImporteeIndex];
85+
const importeeIndexFile = context.fileCache.get(attemptedImporteeIndex);
7186
if (importeeIndexFile) {
87+
Logger.debug(`resolveId: found and resolving ${attemptedImporteeIndex}`);
7288
return attemptedImporteeIndex;
7389
}
7490
}
7591
}
7692
}
77-
7893
return null;
7994
}
8095

0 commit comments

Comments
 (0)