UNPKG

19.4 kBMarkdownView Raw
1<div align="center">
2
3<h1>Fork TS Checker Webpack Plugin</h1>
4<p>Webpack plugin that runs TypeScript type checker on a separate process.</p>
5
6[![npm version](https://img.shields.io/npm/v/fork-ts-checker-webpack-plugin.svg)](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin)
7[![npm beta version](https://img.shields.io/npm/v/fork-ts-checker-webpack-plugin/beta.svg)](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin)
8[![build status](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/workflows/CI/CD/badge.svg?branch=master&event=push)](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/actions?query=branch%3Amaster+event%3Apush)
9[![downloads](http://img.shields.io/npm/dm/fork-ts-checker-webpack-plugin.svg)](https://npmjs.org/package/fork-ts-checker-webpack-plugin)
10[![commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
11[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
12[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
13
14</div>
15
16## Installation
17
18This plugin requires minimum **Node.js 6.11.5**, **webpack 4**, **TypeScript 2.1** and optionally **ESLint 6** (which itself requires minimum **Node.js 8.10.0**)
19
20If you depend on **webpack 2**, **webpack 3**, or **tslint 4**, please use [older version](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/tree/v3.1.1) of the plugin.
21
22```sh
23# with npm
24npm install --save-dev fork-ts-checker-webpack-plugin
25
26# with yarn
27yarn add --dev fork-ts-checker-webpack-plugin
28```
29
30Basic webpack config (with [ts-loader](https://github.com/TypeStrong/ts-loader))
31
32```js
33const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
34
35const webpackConfig = {
36 context: __dirname, // to automatically find tsconfig.json
37 entry: './src/index.ts',
38 module: {
39 rules: [
40 {
41 test: /\.tsx?$/,
42 loader: 'ts-loader',
43 options: {
44 // disable type checker - we will use it in fork plugin
45 transpileOnly: true
46 }
47 }
48 ]
49 },
50 plugins: [new ForkTsCheckerWebpackPlugin()]
51};
52```
53
54## Motivation
55
56There was already similar solution - [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader). You can
57add `CheckerPlugin` and delegate checker to the separate process. The problem with `awesome-typescript-loader` was that, in our case,
58it was a lot slower than [ts-loader](https://github.com/TypeStrong/ts-loader) on an incremental build (~20s vs ~3s).
59Secondly, we used [tslint](https://palantir.github.io/tslint) and we wanted to run this, along with type checker, in a separate process.
60This is why this plugin was created. To provide better performance, the plugin reuses Abstract Syntax Trees between compilations and shares
61these trees with TSLint.
62
63## Modules resolution
64
65It's very important to be aware that **this plugin uses [TypeScript](https://github.com/Microsoft/TypeScript)'s, not
66[webpack](https://github.com/webpack/webpack)'s modules resolution**. It means that you have to setup `tsconfig.json` correctly. For example
67if you set `files: ['./src/someFile.ts']` in `tsconfig.json`, this plugin will check only `someFile.ts` for semantic errors. It's because
68of performance. The goal of this plugin is to be _as fast as possible_. With TypeScript's module resolution we don't have to wait for webpack
69to compile files (which traverses dependency graph during compilation) - we have a full list of files from the begin.
70
71To debug TypeScript's modules resolution, you can use `tsc --traceResolution` command.
72
73## ESLint
74
75[ESLint is the future of linting in the TypeScript world.](https://eslint.org/blog/2019/01/future-typescript-eslint) If you'd like to use eslint with the plugin, supply this option: `eslint: true` and ensure you have the relevant dependencies installed:
76
77`yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --dev`
78
79You should have an ESLint configuration file in your root project directory. Here is a sample `.eslintrc.js` configuration for a TypeScript project:
80
81```js
82const path = require('path');
83module.exports = {
84 parser: '@typescript-eslint/parser', // Specifies the ESLint parser
85 extends: [
86 'plugin:@typescript-eslint/recommended' // Uses the recommended rules from the @typescript-eslint/eslint-plugin
87 ],
88 parserOptions: {
89 project: path.resolve(__dirname, './tsconfig.json'),
90 tsconfigRootDir: __dirname,
91 ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
92 sourceType: 'module', // Allows for the use of imports
93 },
94 rules: {
95 // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
96 // e.g. "@typescript-eslint/explicit-function-return-type": "off",
97 }
98};
99```
100
101There's a good explanation on setting up TypeScript ESLint support by Robert Cooper [here](https://dev.to/robertcoopercode/using-eslint-and-prettier-in-a-typescript-project-53jb).
102
103## Options
104
105- **tsconfig** `string`:
106 Path to _tsconfig.json_ file. Default: `path.resolve(compiler.options.context, './tsconfig.json')`.
107
108- **compilerOptions** `object`:
109 Allows overriding TypeScript options. Should be specified in the same format as you would do for the `compilerOptions` property in tsconfig.json. Default: `{}`.
110
111- **eslint** `true | undefined`:
112
113 - If `true`, this activates eslint support.
114
115- **eslintOptions** `object`:
116
117 - Options that can be used to initialise ESLint. See https://eslint.org/docs/1.0.0/developer-guide/nodejs-api#cliengine
118
119- **async** `boolean`:
120 True by default - `async: false` can block webpack's emit to wait for type checker/linter and to add errors to the webpack's compilation.
121 We recommend to set this to `false` in projects where type checking is faster than webpack's build - it's better for integration with other plugins. Another scenario where you might want to set this to `false` is if you use the `overlay` functionality of `webpack-dev-server`.
122
123- **ignoreDiagnostics** `number[]`:
124 List of TypeScript diagnostic codes to ignore.
125
126- **ignoreLints** `string[]`:
127 List of eslint rule names to ignore.
128
129- **ignoreLintWarnings** `boolean`:
130 If true, will ignore all lint warnings.
131
132- **reportFiles** `string[]`:
133 Only report errors on files matching these glob patterns. This can be useful when certain types definitions have errors that are not fatal to your application. Default: `[]`. Please note that this may behave unexpectedly if using the incremental API as the incremental API doesn't look for global and semantic errors [if it has already found syntactic errors](https://github.com/Microsoft/TypeScript/blob/89386ddda7dafc63cb35560e05412487f47cc267/src/compiler/watch.ts#L141).
134
135```js
136// in webpack.config.js
137new ForkTsCheckerWebpackPlugin({
138 reportFiles: ['src/**/*.{ts,tsx}', '!src/skip.ts']
139});
140```
141
142- **logger** `object`:
143 Logger instance. It should be object that implements method: `error`, `warn`, `info`. Default: `console`.
144
145- **formatter** `'default' | 'codeframe' | (issue: Issue) => string)`:
146 Formatter for issues and lints. By default uses `default` formatter. You can also pass your own formatter as a function
147 (see `src/issue/` and `src/formatter/` for API reference).
148
149- **formatterOptions** `object`:
150 Options passed to formatters (currently only `codeframe` - see [available options](https://www.npmjs.com/package/babel-code-frame#options))
151
152- **silent** `boolean`:
153 If `true`, logger will not be used. Default: `false`.
154
155- **checkSyntacticErrors** `boolean`:
156 This option is useful if you're using ts-loader in `happyPackMode` with [HappyPack](https://github.com/amireh/happypack) or [thread-loader](https://github.com/webpack-contrib/thread-loader) to parallelise your builds. If `true` it will ensure that the plugin checks for _both_ syntactic errors (eg `const array = [{} {}];`) and semantic errors (eg `const x: number = '1';`). By default the plugin only checks for semantic errors. This is because when ts-loader is used in `transpileOnly` mode, ts-loader will still report syntactic errors. When used in `happyPackMode` it does not. Default: `false`.
157
158- **memoryLimit** `number`:
159 Memory limit for service process in MB. If service exits with allocation failed error, increase this number. Default: `2048`.
160
161- **vue** `boolean | { enabled: boolean, compiler: string }`:
162 If `true` or `enabled: true`, the linter and compiler will process VueJs single-file-component (.vue) files. See the
163 [Vue section](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#vue) further down for information on how to correctly setup your project.
164
165- **useTypescriptIncrementalApi** `boolean`:
166 If true, the plugin will use incremental compilation API introduced in TypeScript 2.7. Defaults to `true` when working with TypeScript 3+ and `false` when below 3. The default can be overridden by directly specifying a value.
167 Don't use it together with VueJs enabled - it's not supported yet.
168
169- **measureCompilationTime** `boolean`:
170 If true, the plugin will measure the time spent inside the compilation code. This may be useful to compare modes,
171 especially if there are other loaders/plugins involved in the compilation. **requires Node.js >= 8.5.0**
172
173- **typescript** `string`:
174 If supplied this is a custom path where `typescript` can be found. Defaults to `require.resolve('typescript')`.
175
176- **resolveModuleNameModule** and **resolveTypeReferenceDirectiveModule** `string`:
177 Both of those options refer to files on the disk that respectively export a `resolveModuleName` or a `resolveTypeReferenceDirectiveModule` function. These functions will be used to resolve the import statements and the `<reference types="...">` directives instead of the default TypeScript implementation. Check the following code for an example of what those functions should look like:
178
179 <details>
180 <summary>Code sample</summary>
181
182 ```js
183 const { resolveModuleName } = require(`ts-pnp`);
184
185 exports.resolveModuleName = (
186 typescript,
187 moduleName,
188 containingFile,
189 compilerOptions,
190 resolutionHost
191 ) => {
192 return resolveModuleName(
193 moduleName,
194 containingFile,
195 compilerOptions,
196 resolutionHost,
197 typescript.resolveModuleName
198 );
199 };
200
201 exports.resolveTypeReferenceDirective = (
202 typescript,
203 moduleName,
204 containingFile,
205 compilerOptions,
206 resolutionHost
207 ) => {
208 return resolveModuleName(
209 moduleName,
210 containingFile,
211 compilerOptions,
212 resolutionHost,
213 typescript.resolveTypeReferenceDirective
214 );
215 };
216 ```
217
218</details>
219
220## Different behaviour in watch mode
221
222If you turn on [webpacks watch mode](https://webpack.js.org/configuration/watch/#watch) the `fork-ts-checker-notifier-webpack-plugin` will take care of logging type errors, _not_ webpack itself. That means if you set `silent: true` you won't see type errors in your console in watch mode.
223
224You can either set `silent: false` to show the logging from `fork-ts-checker-notifier-webpack-plugin` _or_ set `async: false`. Now webpack itself will log type errors again, but note that this can slow down your builds depending on the size of your project.
225
226## Notifier
227
228You may already be using the excellent [webpack-notifier](https://github.com/Turbo87/webpack-notifier) plugin to make build failures more obvious in the form of system notifications. There's an equivalent notifier plugin designed to work with the `fork-ts-checker-webpack-plugin`. It is the `fork-ts-checker-notifier-webpack-plugin` and can be found [here](https://github.com/johnnyreilly/fork-ts-checker-notifier-webpack-plugin). This notifier deliberately has a similar API as the `webpack-notifier` plugin to make migration easier.
229
230## Known Issue Watching Non-Emitting Files
231
232At present there is an issue with the plugin regarding the triggering of type-checking when a change is made in a source file that will not emit js. If you have a file which contains only `interface`s and / or `type`s then changes to it will **not** trigger the type checker whilst in watch mode. Sorry about that.
233
234We hope this will be resolved in future; the issue can be tracked [here](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/issues/36).
235
236## Plugin Hooks
237
238This plugin provides some custom webpack hooks (all are sync):
239
240| Hook Access Key | Description | Params |
241| -------------------- | ------------------------------------------------------------------------------ | --------------------------------- |
242| `cancel` | Cancellation has been requested | `cancellationToken` |
243| `waiting` | Waiting for results | - |
244| `serviceBeforeStart` | Async plugin that can be used for delaying `fork-ts-checker-service-start` | - |
245| `serviceStart` | Service will be started | `tsconfigPath`, `memoryLimit` |
246| `serviceStartError` | Cannot start service | `error` |
247| `serviceOutOfMemory` | Service is out of memory | - |
248| `receive` | Plugin receives diagnostics and lints from service | `diagnostics`, `lints` |
249| `emit` | Service will add errors and warnings to webpack compilation ('build' mode) | `diagnostics`, `lints`, `elapsed` |
250| `done` | Service finished type checking and webpack finished compilation ('watch' mode) | `diagnostics`, `lints`, `elapsed` |
251
252### Accessing plugin hooks
253
254To access plugin hooks and tap into the event, we need to use
255the `getCompilerHooks` static method. When we call this method with a [webpack compiler instance](https://webpack.js.org/api/node/),
256it returns the series of [tapable](https://github.com/webpack/tapable)
257hooks where you can pass in your callbacks.
258
259```js
260// require the plugin
261const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
262// setup compiler with the plugin
263const compiler = webpack({
264 // .. webpack config
265});
266// Optionally add the plugin to the compiler
267// **Don't do this if already added through configuration**
268new ForkTsCheckerWebpackPlugin({
269 silent: true,
270 async: true
271}).apply(compiler);
272// Now get the plugin hooks from compiler
273const tsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(compiler);
274// These hooks provide access to different events
275// =================================================== //
276// The properties of tsCheckerHooks corresponds to the //
277// Hook Access Key of the table above. //
278// =================================================== //
279// Example, if we want to run some code when plugin has received diagnostics
280// and lint
281tsCheckerHooks.receive.tap('yourListenerName', (diagnostics, lint) => {
282 // do something with diagnostics, perhaps show custom message
283 console.log(diagnostics);
284});
285// Say we want to show some message when plugin is waiting for typecheck results
286tsCheckerHooks.waiting.tap('yourListenerName', () => {
287 console.log('waiting for typecheck results');
288});
289```
290
291Calling `.tap()` on any hooks, requires two arguments.
292
293##### `name` (`string`)
294
295The first argument passed to `.tap` is the name of your listener callback (`yourListenerName`).
296It doesn't need to correspond to anything special. It is intended to be used
297[internally](https://github.com/webpack/tapable#interception) as the `name` of
298the hook.
299
300##### `callback` (`function`)
301
302The second argument is the callback function. Depending on the hook you are
303tapping into, several arguments are passed to the function. Do check the table
304above to find out which arguments are passed to which hooks.
305
306### Accessing hooks on Webpack Multi-Compiler instance
307
308The above method will not work on webpack [multi compiler](https://webpack.js.org/api/node/#multicompiler)
309instance. The reason is `getCompilerHooks` expects (at lease as of now) the same
310compiler instance to be passed where the plugin was attached. So in case of
311multi compiler, we need to access individual compiler instances.
312
313```js
314const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
315// setup multi compiler with the plugin
316const compiler = webpack([
317 {
318 // .. webpack config
319 },
320 {
321 // .. webpack config
322 }
323]);
324
325// safely determine if instance is multi-compiler
326if ('compilers' in compiler) {
327 compiler.compilers.forEach(singleCompiler => {
328 // get plugin hooks from the single compiler instance
329 const tsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(
330 singleCompiler
331 );
332 // now access hooks just like before
333 tsCheckerHooks.waiting.tap('yourListenerName', () => {
334 console.log('waiting for typecheck results');
335 });
336 });
337}
338```
339
340## Vue
341
3421. Turn on the vue option in the plugin in your webpack config:
343
344```js
345new ForkTsCheckerWebpackPlugin({
346 vue: true
347});
348```
349Optionally change default [vue-template-compiler](https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler) to [nativescript-vue-template-compiler](https://github.com/nativescript-vue/nativescript-vue/tree/master/packages/nativescript-vue-template-compiler) if you use [nativescript-vue](https://github.com/nativescript-vue/nativescript-vue)
350```
351new ForkTsCheckerWebpackPlugin({
352 vue: { enabled: true, compiler: 'nativescript-vue-template-compiler' }
353});
354```
355
3562. To activate TypeScript in your `.vue` files, you need to ensure your script tag's language attribute is set
357 to `ts` or `tsx` (also make sure you include the `.vue` extension in all your import statements as shown below):
358
359```html
360<script lang="ts">
361 import Hello from '@/components/hello.vue';
362
363 // ...
364</script>
365```
366
3673. Ideally you are also using `ts-loader` (in transpileOnly mode). Your Webpack config rules may look something like this:
368
369```js
370{
371 test: /\.ts$/,
372 loader: 'ts-loader',
373 include: [resolve('src'), resolve('test')],
374 options: {
375 appendTsSuffixTo: [/\.vue$/],
376 transpileOnly: true
377 }
378},
379{
380 test: /\.vue$/,
381 loader: 'vue-loader',
382 options: vueLoaderConfig
383},
384```
385
3864. Ensure your `tsconfig.json` includes .vue files:
387
388```js
389// tsconfig.json
390{
391 "include": [
392 "src/**/*.ts",
393 "src/**/*.vue"
394 ],
395 "exclude": [
396 "node_modules"
397 ]
398}
399```
400
4015. It accepts any wildcard in your TypeScript configuration:
402
403```js
404// tsconfig.json
405{
406 "compilerOptions": {
407
408 // ...
409
410 "baseUrl": ".",
411 "paths": {
412 "@/*": [
413 "src/*"
414 ],
415 "~/*": [
416 "src/*"
417 ]
418 }
419 }
420}
421
422// In a .ts or .vue file...
423import Hello from '@/components/hello.vue'
424```
425
4266. If you are working in **VSCode**, you can get the [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) extension to complete the developer workflow.
427
428## Credits
429
430This plugin was created in [Realytics](https://www.realytics.io/) in 2017. Thank you for supporting Open Source.
431
432## License
433
434MIT License