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

Better sourcemaps #300

Merged
merged 2 commits into from
Nov 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions config/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
var path = require('path');
var webpack = require('webpack');




// for prod builds, we have already done AoT and AoT writes to disk
// so read the JS file from disk
// for dev buids, we actually want to pass in .ts files since we
// don't have .js files on disk, they're exclusively in memory

function getEntryPoint() {
if (process.env.IONIC_ENV === 'prod') {
return '{{TMP}}/app/main.prod.js';
Expand All @@ -21,6 +13,7 @@ function getPlugins() {
return [
// This helps ensure the builds are consistent if source hasn't changed:
new webpack.optimize.OccurrenceOrderPlugin(),

// Try to dedupe duplicated modules, if any:
// Add this back in when Angular fixes the issue: https://github.com/angular/angular-cli/issues/1587
//new DedupePlugin()
Expand All @@ -29,6 +22,20 @@ function getPlugins() {
return [];
}

function getSourcemapLoader() {
if (process.env.IONIC_ENV === 'prod') {
// TODO figure out the disk loader, it's not working yet
return [];
}

return [
{
test: /\.js$/,
loader: path.resolve(path.join(process.cwd(), 'node_modules', '@ionic', 'app-scripts', 'dist', 'loaders', 'typescript-sourcemap-loader-memory.js'))
}
];
}

module.exports = {
entry: getEntryPoint(),
output: {
Expand All @@ -47,7 +54,7 @@ module.exports = {
test: /\.json$/,
loader: 'json'
}
]
].concat(getSourcemapLoader())
},

plugins: getPlugins(),
Expand Down
59 changes: 59 additions & 0 deletions src/loaders/typescript-sourcemap-loader-disk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Logger } from '../util/logger';
import { changeExtension, readFileAsync } from '../util/helpers';

module.exports = function typescriptSourcemapLoaderDisk(source: string, map: string) {
this.cacheable();
var callback = this.async();

if ( this.resourcePath.indexOf('node_modules') > -1) {
// it's not a source file, so use the default
callback(null, source, map);
} else {
// it's a src file
loadBetterSourceMap(this.resourcePath, callback, source, map);
}
};

function loadBetterSourceMap(javascriptFilePath: string, callback: Function, originalSource: any, originalMap: any) {
const sourceMapPath = javascriptFilePath + '.map';
const tsFilePath = changeExtension(javascriptFilePath, '.ts');

let sourceMapContent: string = null;
let typescriptFileContent: string = null;

const readSourceMapPromise = readFileAsync(sourceMapPath);
readSourceMapPromise.then((content: string) => {
sourceMapContent = content;
});

const readTsFilePromise = readFileAsync(tsFilePath);
readTsFilePromise.then((content: string) => {
typescriptFileContent = content;
});

let promises: Promise<any>[] = [];
promises.push(readSourceMapPromise);
promises.push(readTsFilePromise);

Promise.all(promises)
.then(() => {
if (!sourceMapContent || !sourceMapContent.length) {
throw new Error('Failed to read sourcemap file');
} else if (!typescriptFileContent || !typescriptFileContent.length) {
throw new Error('Failed to read typescript file');
} else {
return JSON.parse(sourceMapContent);
}
}).then((sourceMapObject: any) => {
if (!sourceMapObject.sourcesContent || sourceMapObject.sourcesContent.length === 0) {
Logger.debug(`loadBetterSourceMap: Assigning Typescript content to source map for ${javascriptFilePath}`);
sourceMapObject.sourcesContent = [typescriptFileContent];
}
callback(null, originalSource, sourceMapObject);
}).catch((err: Error) => {
Logger.debug(`Failed to generate typescript sourcemaps for ${javascriptFilePath}: ${err.message}`);
// just use the default
callback(null, originalSource, originalMap);
});

}
35 changes: 35 additions & 0 deletions src/loaders/typescript-sourcemap-loader-memory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Logger } from '../util/logger';
import { changeExtension, getContext, transformTmpPathToSrcPath} from '../util/helpers';

module.exports = function typescriptSourcemapLoaderMemory(source: string, map: string) {
this.cacheable();
var callback = this.async();
const context = getContext();
const transformedPath = transformTmpPathToSrcPath(this.resourcePath, context);
const sourceMapPath = transformedPath + '.map';
const sourceMapFile = context.fileCache.get(sourceMapPath);

// get the typescript source if needed
let sourcesContent = source;
const isSrcFile = transformedPath !== this.resourcePath;
if (isSrcFile) {
Logger.debug('typescriptSourcemapLoaderMemory: attempting to use .ts instead of .js for sourcemap');
const modifiedPath = changeExtension(transformedPath, '.ts');
const typescriptFileObject = context.fileCache.get(modifiedPath);
if (typescriptFileObject) {
Logger.debug('typescriptSourcemapLoaderMemory: found the .ts file in memory, using it');
sourcesContent = typescriptFileObject.content;
}
}

if ( sourceMapFile ) {
const sourceMapObject = JSON.parse(sourceMapFile.content);
if (!sourceMapObject.sourcesContent || sourceMapObject.sourcesContent.length === 0) {
sourceMapObject.sourcesContent = [sourcesContent];
}
callback(null, source, sourceMapObject);
} else {
callback(null, source, map);
}
};

47 changes: 31 additions & 16 deletions src/plugins/ion-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { changeExtension } from '../util/helpers';
import { BuildContext } from '../util/interfaces';
import { Logger } from '../util/logger';
import { dirname, join, resolve } from 'path';
import * as pluginutils from 'rollup-pluginutils';


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


return {
name: 'ion-compiler',

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

if (context.tsFiles) {
const file = context.tsFiles[sourcePath];
if (!file || !file.output) {
console.error(`unable to find ${sourcePath}`);
const jsSourcePath = changeExtension(sourcePath, '.js');

if (context.fileCache) {
const file = context.fileCache.get(jsSourcePath);
const map = context.fileCache.get(jsSourcePath + '.map');
if (!file || !file.content) {
Logger.debug(`transform: unable to find ${jsSourcePath}`);
return null;
}

let mapContent: any = null;
if (map.content) {
try {
mapContent = JSON.parse(map.content);
} catch (ex) {
}
}

return {
code: file.output,
map: file.map
code: file.content,
map: mapContent
};
}

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

load(sourcePath: string) {
if (context.tsFiles) {
const file = context.tsFiles[sourcePath];
if (file && file.input) {
return file.input;
if (context.fileCache) {
const file = context.fileCache.get(sourcePath);
if (file && file.content) {
return file.content;
}
}

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

if (context.tsFiles) {
const importerFile = context.tsFiles[importer];
if (importerFile && importerFile.output) {
if (context.fileCache) {
const importerFile = context.fileCache.get(importer);
if (importerFile && importerFile.content) {
const attemptedImporteeBasename = resolve(join(dirname(importer), importee));
const attemptedImportee = attemptedImporteeBasename + '.ts';
const importeeFile = context.tsFiles[attemptedImportee];
const importeeFile = context.fileCache.get(attemptedImportee);
if (importeeFile) {
Logger.debug(`resolveId: found and resolving ${attemptedImportee}`);
return attemptedImportee;
} else {
// rather than a file, the attempedImportee could be a directory
// while via node resolve pattern auto resolves to index file
const attemptedImporteeIndex = resolve(join(attemptedImporteeBasename, 'index.ts'));
const importeeIndexFile = context.tsFiles[attemptedImporteeIndex];
const importeeIndexFile = context.fileCache.get(attemptedImporteeIndex);
if (importeeIndexFile) {
Logger.debug(`resolveId: found and resolving ${attemptedImporteeIndex}`);
return attemptedImporteeIndex;
}
}
}
}

return null;
}

Expand Down
Loading