| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.makeAfterCompile = void 0;
- const path = require("path");
- const webpack = require("webpack");
- const constants = require("./constants");
- const instances_1 = require("./instances");
- const utils_1 = require("./utils");
- /**
- * This returns a function that has options to add assets and also to provide errors to webpack
- * In webpack 4 we can do both during the afterCompile hook
- * In webpack 5 only errors should be provided during aftercompile. Assets should be
- * emitted during the afterProcessAssets hook
- */
- function makeAfterCompile(instance, configFilePath) {
- let getCompilerOptionDiagnostics = true;
- let checkAllFilesForErrors = true;
- return (compilation, callback) => {
- // Don't add errors for child compilations
- if (compilation.compiler.isChild()) {
- callback();
- return;
- }
- if (instance.loaderOptions.transpileOnly) {
- provideAssetsFromSolutionBuilderHost(instance, compilation);
- callback();
- return;
- }
- removeCompilationTSLoaderErrors(compilation, instance.loaderOptions);
- provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath);
- getCompilerOptionDiagnostics = false;
- const modules = determineModules(compilation, instance);
- const filesToCheckForErrors = determineFilesToCheckForErrors(checkAllFilesForErrors, instance);
- checkAllFilesForErrors = false;
- const filesWithErrors = new Map();
- provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance);
- provideSolutionErrorsToWebpack(compilation, modules, instance);
- provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation);
- provideTsBuildInfoFilesToWebpack(instance, compilation);
- provideAssetsFromSolutionBuilderHost(instance, compilation);
- instance.filesWithErrors = filesWithErrors;
- instance.modifiedFiles = undefined;
- instance.projectsMissingSourceMaps = new Set();
- callback();
- };
- }
- exports.makeAfterCompile = makeAfterCompile;
- /**
- * handle compiler option errors after the first compile
- */
- function provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath) {
- if (getCompilerOptionDiagnostics) {
- const { languageService, loaderOptions, compiler, program } = instance;
- const errors = (0, utils_1.formatErrors)(program === undefined
- ? languageService.getCompilerOptionsDiagnostics()
- : program.getOptionsDiagnostics(), loaderOptions, instance.colors, compiler, { file: configFilePath || 'tsconfig.json' }, compilation.compiler.context);
- compilation.errors.push(...errors);
- }
- }
- /**
- * build map of all modules based on normalized filename
- * this is used for quick-lookup when trying to find modules
- * based on filepath
- */
- function determineModules(compilation, { filePathKeyMapper }) {
- const modules = new Map();
- compilation.modules.forEach(module => {
- if (module instanceof webpack.NormalModule && module.resource) {
- const modulePath = filePathKeyMapper(module.resource);
- const existingModules = modules.get(modulePath);
- if (existingModules !== undefined) {
- if (!existingModules.includes(module)) {
- existingModules.push(module);
- }
- }
- else {
- modules.set(modulePath, [module]);
- }
- }
- });
- return modules;
- }
- function determineFilesToCheckForErrors(checkAllFilesForErrors, instance) {
- const { files, modifiedFiles, filesWithErrors, otherFiles } = instance;
- // calculate array of files to check
- const filesToCheckForErrors = new Map();
- if (checkAllFilesForErrors) {
- // check all files on initial run
- for (const [filePath, file] of files) {
- addFileToCheckForErrors(filePath, file);
- }
- for (const [filePath, file] of otherFiles) {
- addFileToCheckForErrors(filePath, file);
- }
- }
- else if (modifiedFiles !== null &&
- modifiedFiles !== undefined &&
- modifiedFiles.size) {
- const reverseDependencyGraph = (0, utils_1.populateReverseDependencyGraph)(instance);
- // check all modified files, and all dependants
- for (const modifiedFileName of modifiedFiles.keys()) {
- for (const fileName of (0, utils_1.collectAllDependants)(reverseDependencyGraph, modifiedFileName).keys()) {
- const fileToCheckForErrors = files.get(fileName) || otherFiles.get(fileName);
- if (fileToCheckForErrors) { //file may have been removed
- addFileToCheckForErrors(fileName, fileToCheckForErrors);
- }
- }
- }
- }
- // re-check files with errors from previous build
- if (filesWithErrors !== undefined) {
- for (const [fileWithErrorName, fileWithErrors] of filesWithErrors) {
- addFileToCheckForErrors(fileWithErrorName, fileWithErrors);
- }
- }
- return filesToCheckForErrors;
- function addFileToCheckForErrors(filePath, file) {
- if (file && !(0, utils_1.isReferencedFile)(instance, filePath)) {
- filesToCheckForErrors.set(filePath, file);
- }
- }
- }
- function provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance) {
- const { compiler, files, loaderOptions, compilerOptions, otherFiles, } = instance;
- const filePathRegex = compilerOptions.allowJs === true
- ? constants.dtsTsTsxJsJsxRegex
- : constants.dtsTsTsxRegex;
- // I’m pretty sure this will never be undefined here
- const program = (0, utils_1.ensureProgram)(instance);
- for (const [filePath, { fileName }] of filesToCheckForErrors.entries()) {
- if (fileName.match(filePathRegex) === null) {
- continue;
- }
- const sourceFile = program && program.getSourceFile(fileName);
- const errors = [];
- if (program && sourceFile) {
- errors.push(...program.getSyntacticDiagnostics(sourceFile), ...program
- .getSemanticDiagnostics(sourceFile)
- // Output file has not been built from source file - this message is redundant with
- // program.getOptionsDiagnostics() separately added in instances.ts
- .filter(({ code }) => code !== 6305));
- }
- if (errors.length > 0) {
- const fileWithError = files.get(filePath) || otherFiles.get(filePath);
- filesWithErrors.set(filePath, fileWithError);
- }
- // if we have access to a webpack module, use that
- const associatedModules = modules.get(instance.filePathKeyMapper(fileName));
- if (associatedModules !== undefined) {
- associatedModules.forEach(module => {
- removeModuleTSLoaderError(module, loaderOptions);
- // append errors
- const formattedErrors = (0, utils_1.formatErrors)(errors, loaderOptions, instance.colors, compiler, { module }, compilation.compiler.context);
- formattedErrors.forEach(error => {
- if (module.addError) {
- module.addError(error);
- }
- else {
- module.errors.push(error);
- }
- });
- compilation.errors.push(...formattedErrors);
- });
- }
- else {
- // otherwise it's a more generic error
- const formattedErrors = (0, utils_1.formatErrors)(errors, loaderOptions, instance.colors, compiler, { file: fileName }, compilation.compiler.context);
- compilation.errors.push(...formattedErrors);
- }
- }
- }
- function provideSolutionErrorsToWebpack(compilation, modules, instance) {
- 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 => {
- removeModuleTSLoaderError(module, loaderOptions);
- // append errors
- const formattedErrors = (0, utils_1.formatErrors)(perFileDiagnostics, loaderOptions, instance.colors, compiler, { module }, compilation.compiler.context);
- formattedErrors.forEach(error => {
- if (module.addError) {
- module.addError(error);
- }
- else {
- module.errors.push(error);
- }
- });
- compilation.errors.push(...formattedErrors);
- });
- }
- else {
- // otherwise it's a more generic error
- const formattedErrors = (0, utils_1.formatErrors)(perFileDiagnostics, loaderOptions, instance.colors, compiler, { file: path.resolve(perFileDiagnostics[0].file.fileName) }, compilation.compiler.context);
- compilation.errors.push(...formattedErrors);
- }
- }
- // Add global solution errors
- compilation.errors.push(...(0, utils_1.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.
- * JavaScript declaration files are included if `allowJs` is set.
- */
- function provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation) {
- const filePathRegex = instance.compilerOptions.allowJs === true
- ? constants.dtsTsTsxJsJsxRegex
- : constants.dtsTsTsxRegex;
- for (const { fileName } of filesToCheckForErrors.values()) {
- if (fileName.match(filePathRegex) === null) {
- continue;
- }
- addDeclarationFilesAsAsset((0, instances_1.getEmitOutput)(instance, fileName), compilation);
- }
- }
- function addDeclarationFilesAsAsset(outputFiles, compilation, skipOutputFile) {
- outputFilesToAsset(outputFiles, compilation, outputFile => skipOutputFile && skipOutputFile(outputFile)
- ? true
- : !outputFile.name.match(constants.dtsDtsxOrDtsDtsxMapRegex));
- }
- function outputFileToAsset(outputFile, compilation) {
- const assetPath = path
- .relative(compilation.compiler.outputPath, outputFile.name)
- // According to @alexander-akait (and @sokra) we should always '/' https://github.com/TypeStrong/ts-loader/pull/1251#issuecomment-799606985
- .replace(/\\/g, '/');
- // As suggested by @JonWallsten here: https://github.com/TypeStrong/ts-loader/pull/1251#issuecomment-800032753
- compilation.emitAsset(assetPath, new webpack.sources.RawSource(outputFile.text));
- }
- function outputFilesToAsset(outputFiles, compilation, skipOutputFile) {
- for (const outputFile of outputFiles) {
- if (!skipOutputFile || !skipOutputFile(outputFile)) {
- outputFileToAsset(outputFile, compilation);
- }
- }
- }
- /**
- * gather all .tsbuildinfo for the project
- */
- function provideTsBuildInfoFilesToWebpack(instance, compilation) {
- if (instance.watchHost) {
- // Ensure emit is complete
- (0, instances_1.getEmitFromWatchHost)(instance);
- if (instance.watchHost.tsbuildinfo) {
- outputFileToAsset(instance.watchHost.tsbuildinfo, compilation);
- }
- instance.watchHost.outputFiles.clear();
- instance.watchHost.tsbuildinfo = undefined;
- }
- }
- /**
- * gather all solution builder assets
- */
- function provideAssetsFromSolutionBuilderHost(instance, compilation) {
- if (instance.solutionBuilderHost) {
- // written files
- outputFilesToAsset(instance.solutionBuilderHost.writtenFiles, compilation);
- instance.solutionBuilderHost.writtenFiles.length = 0;
- }
- }
- /**
- * handle all other errors. The basic approach here to get accurate error
- * reporting is to start with a "blank slate" each compilation and gather
- * all errors from all files. Since webpack tracks errors in a module from
- * compilation-to-compilation, and since not every module always runs through
- * the loader, we need to detect and remove any pre-existing errors.
- */
- function removeCompilationTSLoaderErrors(compilation, loaderOptions) {
- compilation.errors = compilation.errors.filter(error => error.details !== (0, utils_1.tsLoaderSource)(loaderOptions));
- }
- function removeModuleTSLoaderError(module, loaderOptions) {
- const warnings = module.getWarnings();
- const errors = module.getErrors();
- module.clearWarningsAndErrors();
- Array.from(warnings || []).forEach(warning => module.addWarning(warning));
- Array.from(errors || [])
- .filter((error) => error.loaderSource !== (0, utils_1.tsLoaderSource)(loaderOptions))
- .forEach(error => module.addError(error));
- }
- //# sourceMappingURL=after-compile.js.map
|