Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SolutionBuilder watches #1003

Merged
merged 19 commits into from Sep 19, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions package.json
Expand Up @@ -7,11 +7,11 @@
"scripts": {
"build": "tsc --version && tsc --project \"./src\"",
"lint": "tslint --project \"./src\"",
"comparison-tests": "tsc --project \"./test/comparison-tests\" && npm link ./test/comparison-tests/testLib && node test/comparison-tests/run-tests.js",
"comparison-tests-generate": "node test/comparison-tests/stub-new-version.js",
"comparison-tests": "git clean -xfd test/comparison-tests && tsc --project \"./test/comparison-tests\" && npm link ./test/comparison-tests/testLib && node test/comparison-tests/run-tests.js",
"comparison-tests-generate": "git clean -xfd test/comparison-tests && node test/comparison-tests/stub-new-version.js",
"execution-tests": "git clean -xfd test/execution-tests && node test/execution-tests/run-tests.js",
"test": "git clean -xfd test/execution-tests && node test/run-tests.js",
"clean": "git clean -xfd test/execution-tests",
"test": "git clean -xfd test/comparison-tests && git clean -xfd test/execution-tests && node test/run-tests.js",
"clean": "git clean -xfd test/comparison-tests && git clean -xfd test/execution-tests",
"docker:build": "docker build -t ts-loader .",
"postdocker:build": "docker run -it ts-loader yarn test"
},
Expand Down
118 changes: 116 additions & 2 deletions src/after-compile.ts
Expand Up @@ -3,7 +3,7 @@ import * as ts from 'typescript';
import * as webpack from 'webpack';

import * as constants from './constants';
import { getEmitOutput } from './instances';
import { forEachResolvedProjectReference, getEmitOutput } from './instances';
import {
TSFile,
TSFiles,
Expand Down Expand Up @@ -68,6 +68,9 @@ export function makeAfterCompile(
compilation
);

provideSolutionErrorsToWebpack(compilation, modules, instance);
provideTsBuildInfoFilesToWebpack(instance, compilation);

instance.filesWithErrors = filesWithErrors;
instance.modifiedFiles = null;
instance.projectsMissingSourceMaps = new Set();
Expand Down Expand Up @@ -195,7 +198,6 @@ function provideErrorsToWebpack(
}

const sourceFile = program && program.getSourceFile(filePath);

// If the source file is undefined, that probably means it’s actually part of an unbuilt project reference,
// which will have already produced a more useful error than the one we would get by proceeding here.
// If it’s undefined and we’re not using project references at all, I guess carry on so the user will
Expand Down Expand Up @@ -256,6 +258,76 @@ function provideErrorsToWebpack(
}
}

function provideSolutionErrorsToWebpack(
compilation: webpack.compilation.Compilation,
modules: Map<string, WebpackModule[]>,
instance: TSInstance
) {
if (
!instance.solutionBuilderHost ||
!(
instance.solutionBuilderHost.diagnostics.global.length ||
instance.solutionBuilderHost.diagnostics.perFile.size
)
) {
return;
}

const {
compiler,
loaderOptions,
solutionBuilderHost: { diagnostics }
} = instance;

for (const [filePath, perFileDiagnostics] of diagnostics.perFile) {
// if we have access to a webpack module, use that
const associatedModules = modules.get(filePath);
if (associatedModules !== undefined) {
associatedModules.forEach(module => {
// remove any existing errors
removeTSLoaderErrors(module.errors);

// append errors
const formattedErrors = formatErrors(
perFileDiagnostics,
loaderOptions,
instance.colors,
compiler,
{ module },
compilation.compiler.context
);

module.errors.push(...formattedErrors);
compilation.errors.push(...formattedErrors);
});
} else {
// otherwise it's a more generic error
const formattedErrors = formatErrors(
perFileDiagnostics,
loaderOptions,
instance.colors,
compiler,
{ file: filePath },
compilation.compiler.context
);

compilation.errors.push(...formattedErrors);
}
}

// Add global solution errors
compilation.errors.push(
...formatErrors(
diagnostics.global,
instance.loaderOptions,
instance.colors,
instance.compiler,
{ file: 'tsconfig.json' },
compilation.compiler.context
)
);
}

/**
* gather all declaration files from TypeScript and output them to webpack
*/
Expand Down Expand Up @@ -287,6 +359,48 @@ function provideDeclarationFilesToWebpack(
}
}

/**
* gather all .tsbuildinfo for the project
*/
function provideTsBuildInfoFilesToWebpack(
instance: TSInstance,
compilation: webpack.compilation.Compilation
) {
if (instance.solutionBuilderHost && instance.modifiedFiles) {
const program = ensureProgram(instance);
if (program) {
forEachResolvedProjectReference(
program.getResolvedProjectReferences(),
resolvedRef => {
if (
resolvedRef.commandLine.fileNames.some(f =>
instance.modifiedFiles!.has(path.resolve(f))
)
) {
// TODO:: update compiler to expose this
const buildInfoPath = (instance.compiler as any).getOutputPathForBuildInfo(
resolvedRef.commandLine.options
);
if (buildInfoPath) {
const text = instance.compiler.sys.readFile(buildInfoPath);
if (text) {
const assetPath = path.relative(
compilation.compiler.outputPath,
path.resolve(buildInfoPath)
);
compilation.assets[assetPath] = {
source: () => text,
size: () => text.length
};
}
}
}
}
);
}
}
}

/**
* handle all other errors. The basic approach here to get accurate error
* reporting is to start with a "blank slate" each compilation and gather
Expand Down