123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- const chalk_1 = require("chalk");
- const fs = require("fs");
- const path = require("path");
- const after_compile_1 = require("./after-compile");
- const compilerSetup_1 = require("./compilerSetup");
- const config_1 = require("./config");
- const constants_1 = require("./constants");
- const logger = require("./logger");
- const servicesHost_1 = require("./servicesHost");
- const utils_1 = require("./utils");
- const watch_run_1 = require("./watch-run");
- const instances = {};
- /**
- * The loader is executed once for each file seen by webpack. However, we need to keep
- * a persistent instance of TypeScript that contains all of the files in the program
- * along with definition files and options. This function either creates an instance
- * or returns the existing one. Multiple instances are possible by using the
- * `instance` property.
- */
- function getTypeScriptInstance(loaderOptions, loader) {
- if (instances.hasOwnProperty(loaderOptions.instance)) {
- const instance = instances[loaderOptions.instance];
- utils_1.ensureProgram(instance);
- return { instance: instances[loaderOptions.instance] };
- }
- const colors = new chalk_1.default.constructor({ enabled: loaderOptions.colors });
- const log = logger.makeLogger(loaderOptions, colors);
- const compiler = compilerSetup_1.getCompiler(loaderOptions, log);
- if (compiler.errorMessage !== undefined) {
- return { error: utils_1.makeError(colors.red(compiler.errorMessage), undefined) };
- }
- return successfulTypeScriptInstance(loaderOptions, loader, log, colors, compiler.compiler, compiler.compilerCompatible, compiler.compilerDetailsLogMessage);
- }
- exports.getTypeScriptInstance = getTypeScriptInstance;
- function successfulTypeScriptInstance(loaderOptions, loader, log, colors, compiler, compilerCompatible, compilerDetailsLogMessage) {
- const configFileAndPath = config_1.getConfigFile(compiler, colors, loader, loaderOptions, compilerCompatible, log, compilerDetailsLogMessage);
- if (configFileAndPath.configFileError !== undefined) {
- const { message, file } = configFileAndPath.configFileError;
- return {
- error: utils_1.makeError(colors.red('error while reading tsconfig.json:' + constants_1.EOL + message), file)
- };
- }
- const { configFilePath, configFile } = configFileAndPath;
- const basePath = loaderOptions.context || path.dirname(configFilePath || '');
- const configParseResult = config_1.getConfigParseResult(compiler, configFile, basePath);
- if (configParseResult.errors.length > 0 && !loaderOptions.happyPackMode) {
- const errors = utils_1.formatErrors(configParseResult.errors, loaderOptions, colors, compiler, { file: configFilePath }, loader.context);
- loader._module.errors.push(...errors);
- return {
- error: utils_1.makeError(colors.red('error while parsing tsconfig.json'), configFilePath)
- };
- }
- const compilerOptions = compilerSetup_1.getCompilerOptions(configParseResult);
- const files = new Map();
- const otherFiles = new Map();
- const appendTsTsxSuffixesIfRequired = loaderOptions.appendTsSuffixTo.length > 0 ||
- loaderOptions.appendTsxSuffixTo.length > 0
- ? (filePath) => utils_1.appendSuffixesIfMatch({
- '.ts': loaderOptions.appendTsSuffixTo,
- '.tsx': loaderOptions.appendTsxSuffixTo
- }, filePath)
- : (filePath) => filePath;
- // same strategy as https://github.com/s-panferov/awesome-typescript-loader/pull/531/files
- let { getCustomTransformers: customerTransformers } = loaderOptions;
- let getCustomTransformers = Function.prototype;
- if (typeof customerTransformers === 'function') {
- getCustomTransformers = customerTransformers;
- }
- else if (typeof customerTransformers === 'string') {
- try {
- customerTransformers = require(customerTransformers);
- }
- catch (err) {
- throw new Error(`Failed to load customTransformers from "${loaderOptions.getCustomTransformers}": ${err.message}`);
- }
- if (typeof customerTransformers !== 'function') {
- throw new Error(`Custom transformers in "${loaderOptions.getCustomTransformers}" should export a function, got ${typeof getCustomTransformers}`);
- }
- getCustomTransformers = customerTransformers;
- }
- if (loaderOptions.transpileOnly) {
- // quick return for transpiling
- // we do need to check for any issues with TS options though
- const program = configParseResult.projectReferences !== undefined
- ? compiler.createProgram({
- rootNames: configParseResult.fileNames,
- options: configParseResult.options,
- projectReferences: configParseResult.projectReferences
- })
- : compiler.createProgram([], compilerOptions);
- // happypack does not have _module.errors - see https://github.com/TypeStrong/ts-loader/issues/336
- if (!loaderOptions.happyPackMode) {
- const diagnostics = program.getOptionsDiagnostics();
- const errors = utils_1.formatErrors(diagnostics, loaderOptions, colors, compiler, { file: configFilePath || 'tsconfig.json' }, loader.context);
- loader._module.errors.push(...errors);
- }
- instances[loaderOptions.instance] = {
- compiler,
- compilerOptions,
- appendTsTsxSuffixesIfRequired,
- loaderOptions,
- files,
- otherFiles,
- program,
- dependencyGraph: {},
- reverseDependencyGraph: {},
- transformers: getCustomTransformers(program),
- colors
- };
- return { instance: instances[loaderOptions.instance] };
- }
- // Load initial files (core lib files, any files specified in tsconfig.json)
- let normalizedFilePath;
- try {
- const filesToLoad = loaderOptions.onlyCompileBundledFiles
- ? configParseResult.fileNames.filter(fileName => constants_1.dtsDtsxOrDtsDtsxMapRegex.test(fileName))
- : configParseResult.fileNames;
- filesToLoad.forEach(filePath => {
- normalizedFilePath = path.normalize(filePath);
- files.set(normalizedFilePath, {
- text: fs.readFileSync(normalizedFilePath, 'utf-8'),
- version: 0
- });
- });
- }
- catch (exc) {
- return {
- error: utils_1.makeError(colors.red(`A file specified in tsconfig.json could not be found: ${normalizedFilePath}`), normalizedFilePath)
- };
- }
- // if allowJs is set then we should accept js(x) files
- const scriptRegex = configParseResult.options.allowJs === true
- ? /\.tsx?$|\.jsx?$/i
- : /\.tsx?$/i;
- const instance = (instances[loaderOptions.instance] = {
- compiler,
- compilerOptions,
- appendTsTsxSuffixesIfRequired,
- loaderOptions,
- files,
- otherFiles,
- languageService: null,
- version: 0,
- transformers: {},
- dependencyGraph: {},
- reverseDependencyGraph: {},
- modifiedFiles: null,
- colors
- });
- if (!loader._compiler.hooks) {
- throw new Error("You may be using an old version of webpack; please check you're using at least version 4");
- }
- if (loaderOptions.experimentalWatchApi && compiler.createWatchProgram) {
- log.logInfo('Using watch api');
- // If there is api available for watch, use it instead of language service
- instance.watchHost = servicesHost_1.makeWatchHost(scriptRegex, log, loader, instance, configParseResult.projectReferences);
- instance.watchOfFilesAndCompilerOptions = compiler.createWatchProgram(instance.watchHost);
- instance.program = instance.watchOfFilesAndCompilerOptions
- .getProgram()
- .getProgram();
- instance.transformers = getCustomTransformers(instance.program);
- }
- else {
- const servicesHost = servicesHost_1.makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.experimentalFileCaching, configParseResult.projectReferences);
- instance.languageService = compiler.createLanguageService(servicesHost.servicesHost, compiler.createDocumentRegistry());
- if (servicesHost.clearCache !== null) {
- loader._compiler.hooks.watchRun.tap('ts-loader', servicesHost.clearCache);
- }
- instance.transformers = getCustomTransformers(instance.languageService.getProgram());
- }
- loader._compiler.hooks.afterCompile.tapAsync('ts-loader', after_compile_1.makeAfterCompile(instance, configFilePath));
- loader._compiler.hooks.watchRun.tapAsync('ts-loader', watch_run_1.makeWatchRun(instance));
- return { instance };
- }
- function getEmitOutput(instance, filePath) {
- const program = utils_1.ensureProgram(instance);
- if (program !== undefined) {
- const outputFiles = [];
- const writeFile = (fileName, text, writeByteOrderMark) => outputFiles.push({ name: fileName, writeByteOrderMark, text });
- const sourceFile = program.getSourceFile(filePath);
- // The source file will be undefined if it’s part of an unbuilt project reference
- if (sourceFile !== undefined || !utils_1.isUsingProjectReferences(instance)) {
- program.emit(sourceFile, writeFile,
- /*cancellationToken*/ undefined,
- /*emitOnlyDtsFiles*/ false, instance.transformers);
- }
- return outputFiles;
- }
- else {
- // Emit Javascript
- return instance.languageService.getProgram().getSourceFile(filePath) ===
- undefined
- ? []
- : instance.languageService.getEmitOutput(filePath).outputFiles;
- }
- }
- exports.getEmitOutput = getEmitOutput;
|