Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyreilly committed Jan 20, 2018
2 parents c598da3 + 3d41633 commit c6354c1
Show file tree
Hide file tree
Showing 213 changed files with 11,258 additions and 80 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Expand Up @@ -3,17 +3,17 @@ addons:
chrome: stable
language: node_js
node_js:
- "4"
- "6"
- "8"
sudo: false
sudo: required
install:
- yarn install
- yarn build
- yarn add $TYPESCRIPT
env:
- TYPESCRIPT=typescript@2.6.1
- TYPESCRIPT=typescript@2.7.0-rc
- TYPESCRIPT=typescript@next
- TYPESCRIPT=typescript@2.6.1
- TYPESCRIPT=typescript@2.5.2
- TYPESCRIPT=typescript@2.4.1
- TYPESCRIPT=typescript@2.3.1
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog

## v3.3.0

- [Report diagnostics only on certain files with `reportFiles` option](https://github.com/TypeStrong/ts-loader/pull/701) - thanks @freeman!
- [Added support for the new watch api of TypeScript compiler.](https://github.com/TypeStrong/ts-loader/pull/685) nb This feature has been placed behind a new `experimentalWatchApi` option until it has been thoroughly tested. All being well it is likely to become the default behaviour for ts-loader in future - thanks @sheetalkamat!

## v3.2.0

- [Add new loader option `contextAsConfigBasePath`](https://github.com/TypeStrong/ts-loader/pull/681) - thanks @christiantinauer
Expand Down
33 changes: 33 additions & 0 deletions README.md
Expand Up @@ -156,6 +156,24 @@ The build **should** fail on TypeScript compilation errors as of webpack 2. If f

For more background have a read of [this issue](https://github.com/TypeStrong/ts-loader/issues/108).

### `baseUrl` / `paths` module resolution

If you want to resolve modules according to `baseUrl` and `paths` in your `tsconfig.json` then you can use the [tsconfig-paths-webpack-plugin](https://www.npmjs.com/package/tsconfig-paths-webpack-plugin) package. For details about this functionality, see the [module resolution documentation](https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url).

This feature requires webpack 2.1+ and TypeScript 2.0+. Use the config below or check the [package](https://github.com/dividab/tsconfig-paths-webpack-plugin/blob/master/README.md) for more information on usage.

```js
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
...
resolve: {
plugins: [new TsconfigPathsPlugin({ /*configFile: "./path/to/tsconfig.json" */ })]
}
...
}
```

### Options

There are two types of options: TypeScript options (aka "compiler options") and loader options. TypeScript options should be set using a tsconfig.json file. Loader options can be specified through the `options` property in the webpack configuration:
Expand Down Expand Up @@ -227,6 +245,21 @@ messages are emitted via webpack which is not affected by this flag.
You can squelch certain TypeScript errors by specifying an array of diagnostic
codes to ignore.

#### reportFiles *(string[]) (default=[])*

Only report errors on files matching these glob patterns.

```javascript
// in webpack.config.js
{
test: /\.ts$/,
loader: 'ts-loader',
options: { reportFiles: ['src/**/*.{ts,tsx}', '!src/skip.ts'] }
}
```

This can be useful when certain types definitions have errors that are not fatal to your application.

#### compiler *(string) (default='typescript')*

Allows use of TypeScript compilers other than the official one. Should be
Expand Down
3 changes: 2 additions & 1 deletion appveyor.yml
Expand Up @@ -3,8 +3,9 @@ environment:
FORCE_COLOR: 1
nodejs_version: "8"
matrix:
- TYPESCRIPT: typescript@2.6.1
- TYPESCRIPT: typescript@2.7.0-rc
- TYPESCRIPT: typescript@next
- TYPESCRIPT: typescript@2.6.1
- TYPESCRIPT: typescript@2.5.2
- TYPESCRIPT: typescript@2.4.1
- TYPESCRIPT: typescript@2.3.1
Expand Down
8 changes: 5 additions & 3 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "ts-loader",
"version": "3.2.0",
"version": "3.3.0",
"description": "TypeScript loader for webpack",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -39,9 +39,11 @@
"chalk": "^2.3.0",
"enhanced-resolve": "^3.0.0",
"loader-utils": "^1.0.2",
"micromatch": "^3.1.4",
"semver": "^5.0.1"
},
"devDependencies": {
"@types/micromatch": "^3.1.0",
"@types/semver": "^5.4.0",
"babel": "^6.0.0",
"babel-core": "^6.0.0",
Expand All @@ -60,11 +62,11 @@
"karma-jasmine": "^1.0.0",
"karma-mocha-reporter": "^2.0.0",
"karma-sourcemap-loader": "^0.3.6",
"karma-webpack": "^2.0.1",
"karma-webpack": "2.0.6",
"mkdirp": "^0.5.1",
"mocha": "^4.0.0",
"rimraf": "^2.6.2",
"typescript": "^2.6.1",
"typescript": "^2.7.0-dev.20180120",
"webpack": "^3.6.0"
}
}
47 changes: 31 additions & 16 deletions src/after-compile.ts
@@ -1,5 +1,4 @@
import * as path from 'path';
import * as typescript from 'typescript';

import { collectAllDependants, formatErrors, hasOwnProperty, registerWebpackErrors } from './utils';
import * as constants from './constants';
Expand All @@ -10,6 +9,7 @@ import {
WebpackError,
WebpackModule
} from './interfaces';
import { getEmitOutput } from './instances';

export function makeAfterCompile(
instance: TSInstance,
Expand Down Expand Up @@ -38,7 +38,7 @@ export function makeAfterCompile(
const filesWithErrors: TSFiles = {};
provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance);

provideDeclarationFilesToWebpack(filesToCheckForErrors, instance.languageService!, compilation);
provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation);

instance.filesWithErrors = filesWithErrors;
instance.modifiedFiles = null;
Expand All @@ -60,13 +60,16 @@ function provideCompilerOptionDiagnosticErrorsToWebpack(
configFilePath: string | undefined
) {
if (getCompilerOptionDiagnostics) {
const { languageService, loaderOptions, compiler } = instance;
const { languageService, loaderOptions, compiler, program } = instance;
registerWebpackErrors(
compilation.errors,
formatErrors(
languageService!.getCompilerOptionsDiagnostics(),
program ?
program.getOptionsDiagnostics() :
languageService!.getCompilerOptionsDiagnostics(),
loaderOptions, instance.colors, compiler,
{ file: configFilePath || 'tsconfig.json' }));
{ file: configFilePath || 'tsconfig.json' },
compilation.compiler.context));
}
}

Expand Down Expand Up @@ -99,18 +102,23 @@ function determineFilesToCheckForErrors(
checkAllFilesForErrors: boolean,
instance: TSInstance
) {
const { files, modifiedFiles, filesWithErrors } = instance
const { files, modifiedFiles, filesWithErrors, otherFiles } = instance
// calculate array of files to check
let filesToCheckForErrors: TSFiles = {};
if (checkAllFilesForErrors) {
// check all files on initial run
filesToCheckForErrors = files;
Object.keys(files).forEach(fileName => {
filesToCheckForErrors[fileName] = files[fileName];
});
Object.keys(otherFiles).forEach(fileName => {
filesToCheckForErrors[fileName] = otherFiles[fileName];
});
} else if (modifiedFiles !== null && modifiedFiles !== undefined) {
// check all modified files, and all dependants
Object.keys(modifiedFiles).forEach(modifiedFileName => {
collectAllDependants(instance.reverseDependencyGraph, modifiedFileName)
.forEach(fileName => {
filesToCheckForErrors[fileName] = files[fileName];
filesToCheckForErrors[fileName] = files[fileName] || otherFiles[fileName];
});
});
}
Expand All @@ -131,16 +139,19 @@ function provideErrorsToWebpack(
modules: Modules,
instance: TSInstance
) {
const { compiler, languageService, files, loaderOptions, compilerOptions } = instance;
const { compiler, program, languageService, files, loaderOptions, compilerOptions, otherFiles } = instance;

let filePathRegex = !!compilerOptions.checkJs ? constants.dtsTsTsxJsJsxRegex : constants.dtsTsTsxRegex;

Object.keys(filesToCheckForErrors)
.filter(filePath => filePath.match(filePathRegex))
.forEach(filePath => {
const errors = languageService!.getSyntacticDiagnostics(filePath).concat(languageService!.getSemanticDiagnostics(filePath));
const sourceFile = program && program.getSourceFile(filePath);
const errors = program ?
program.getSyntacticDiagnostics(sourceFile).concat(program.getSemanticDiagnostics(sourceFile)) :
languageService!.getSyntacticDiagnostics(filePath).concat(languageService!.getSemanticDiagnostics(filePath));
if (errors.length > 0) {
filesWithErrors[filePath] = files[filePath];
filesWithErrors[filePath] = files[filePath] || otherFiles[filePath];
}

// if we have access to a webpack module, use that
Expand All @@ -152,13 +163,17 @@ function provideErrorsToWebpack(
removeTSLoaderErrors(module.errors);

// append errors
const formattedErrors = formatErrors(errors, loaderOptions, instance.colors, compiler, { module });
const formattedErrors = formatErrors(errors, loaderOptions,
instance.colors, compiler, { module },
compilation.compiler.context);
registerWebpackErrors(module.errors, formattedErrors);
registerWebpackErrors(compilation.errors, formattedErrors);
});
} else {
// otherwise it's a more generic error
registerWebpackErrors(compilation.errors, formatErrors(errors, loaderOptions, instance.colors, compiler, { file: filePath }));
registerWebpackErrors(compilation.errors, formatErrors(errors,
loaderOptions, instance.colors, compiler, { file: filePath },
compilation.compiler.context));
}
});
}
Expand All @@ -168,14 +183,14 @@ function provideErrorsToWebpack(
*/
function provideDeclarationFilesToWebpack(
filesToCheckForErrors: TSFiles,
languageService: typescript.LanguageService,
instance: TSInstance,
compilation: WebpackCompilation
) {
Object.keys(filesToCheckForErrors)
.filter(filePath => filePath.match(constants.tsTsxRegex))
.forEach(filePath => {
const output = languageService.getEmitOutput(filePath);
const declarationFile = output.outputFiles.filter(outputFile => outputFile.name.match(constants.dtsDtsxRegex)).pop();
const outputFiles = getEmitOutput(instance, filePath);
const declarationFile = outputFiles.filter(outputFile => outputFile.name.match(constants.dtsDtsxRegex)).pop();
if (declarationFile !== undefined) {
const assetPath = path.relative(compilation.compiler.context, declarationFile.name);
compilation.assets[assetPath] = {
Expand Down
3 changes: 2 additions & 1 deletion src/config.ts
Expand Up @@ -40,7 +40,8 @@ export function getConfigFile(
);

if (configFile.error !== undefined) {
configFileError = formatErrors([configFile.error], loaderOptions, colors, compiler, { file: configFilePath })[0];
configFileError = formatErrors([configFile.error], loaderOptions,
colors, compiler, { file: configFilePath }, loader.context)[0];
}
} else {
if (compilerCompatible) { log.logInfo(compilerDetailsLogMessage); }
Expand Down
47 changes: 38 additions & 9 deletions src/index.ts
@@ -1,7 +1,8 @@
import * as path from 'path';
import * as loaderUtils from 'loader-utils';
import * as typescript from 'typescript';

import { getTypeScriptInstance } from './instances';
import { getTypeScriptInstance, getEmitOutput } from './instances';
import { appendSuffixesIfMatch, arrify, formatErrors, hasOwnProperty, registerWebpackErrors } from './utils';
import * as constants from './constants';
import {
Expand Down Expand Up @@ -110,7 +111,7 @@ function getLoaderOptions(loader: Webpack) {
}

type ValidLoaderOptions = keyof LoaderOptions;
const validLoaderOptions: ValidLoaderOptions[] = ['silent', 'logLevel', 'logInfoToStdOut', 'instance', 'compiler', 'context', 'configFile', 'transpileOnly', 'ignoreDiagnostics', 'errorFormatter', 'colors', 'compilerOptions', 'appendTsSuffixTo', 'appendTsxSuffixTo', 'entryFileCannotBeJs' /* DEPRECATED */, 'onlyCompileBundledFiles', 'happyPackMode', 'getCustomTransformers'];
const validLoaderOptions: ValidLoaderOptions[] = ['silent', 'logLevel', 'logInfoToStdOut', 'instance', 'compiler', 'context', 'configFile', 'transpileOnly', 'ignoreDiagnostics', 'errorFormatter', 'colors', 'compilerOptions', 'appendTsSuffixTo', 'appendTsxSuffixTo', 'entryFileCannotBeJs' /* DEPRECATED */, 'onlyCompileBundledFiles', 'happyPackMode', 'getCustomTransformers', 'reportFiles', 'experimentalWatchApi'];

/**
* Validate the supplied loader options.
Expand Down Expand Up @@ -152,7 +153,10 @@ function makeLoaderOptions(instanceName: string, configFileOptions: Partial<Load
entryFileCannotBeJs: false,
happyPackMode: false,
colors: true,
onlyCompileBundledFiles: false
onlyCompileBundledFiles: false,
reportFiles: [],
// When the watch API usage stabilises look to remove this option and make watch usage the default behaviour when available
experimentalWatchApi: false
} as Partial<LoaderOptions>, configFileOptions, loaderOptions);

options.ignoreDiagnostics = arrify(options.ignoreDiagnostics).map(Number);
Expand All @@ -170,16 +174,40 @@ function makeLoaderOptions(instanceName: string, configFileOptions: Partial<Load
* Also add the file to the modified files
*/
function updateFileInCache(filePath: string, contents: string, instance: TSInstance) {
let fileWatcherEventKind: typescript.FileWatcherEventKind | undefined;
// Update file contents
let file = instance.files[filePath];
if (file === undefined) {
file = instance.files[filePath] = <TSFile>{ version: 0 };
file = instance.otherFiles[filePath];
if (file !== undefined) {
delete instance.otherFiles[filePath];
instance.files[filePath] = file;
}
else {
if (instance.watchHost) {
fileWatcherEventKind = instance.compiler.FileWatcherEventKind.Created;
}
file = instance.files[filePath] = <TSFile>{ version: 0 };
}
instance.changedFilesList = true;
}

if (instance.watchHost && contents === undefined) {
fileWatcherEventKind = instance.compiler.FileWatcherEventKind.Deleted;
}

if (file.text !== contents) {
file.version++;
file.text = contents;
instance.version!++;
if (instance.watchHost && fileWatcherEventKind === undefined) {
instance.watchHost.invokeFileWatcher(filePath, instance.compiler.FileWatcherEventKind.Changed);
}
}

if (instance.watchHost && fileWatcherEventKind !== undefined) {
instance.watchHost.invokeFileWatcher(filePath, fileWatcherEventKind);
instance.watchHost.invokeDirectoryWatcher(path.dirname(filePath), filePath);
}

// push this file to modified files hash.
Expand All @@ -196,8 +224,7 @@ function getEmit(
instance: TSInstance,
loader: Webpack
) {
// Emit Javascript
const output = instance.languageService!.getEmitOutput(filePath);
const outputFiles = getEmitOutput(instance, filePath);

loader.clearDependencies();
loader.addDependency(rawFilePath);
Expand All @@ -221,10 +248,10 @@ function getEmit(
.concat(additionalDependencies)
.map(defFilePath => defFilePath + '@' + (instance.files[defFilePath] || { version: '?' }).version);

const outputFile = output.outputFiles.filter(outputFile => outputFile.name.match(constants.jsJsx)).pop();
const outputFile = outputFiles.filter(outputFile => outputFile.name.match(constants.jsJsx)).pop();
const outputText = (outputFile) ? outputFile.text : undefined;

const sourceMapFile = output.outputFiles.filter(outputFile => outputFile.name.match(constants.jsJsxMap)).pop();
const sourceMapFile = outputFiles.filter(outputFile => outputFile.name.match(constants.jsJsxMap)).pop();
const sourceMapText = (sourceMapFile) ? sourceMapFile.text : undefined;

return { outputText, sourceMapText };
Expand Down Expand Up @@ -252,7 +279,9 @@ function getTranspilationEmit(
if (!instance.loaderOptions.happyPackMode) {
registerWebpackErrors(
loader._module.errors,
formatErrors(diagnostics, instance.loaderOptions, instance.colors, instance.compiler, { module: loader._module })
formatErrors(diagnostics, instance.loaderOptions, instance.colors,
instance.compiler, { module: loader._module },
loader.context)
);
}

Expand Down

0 comments on commit c6354c1

Please sign in to comment.