web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

434 lines
19 KiB

  1. <div align="center">
  2. <h1>Fork TS Checker Webpack Plugin</h1>
  3. <p>Webpack plugin that runs TypeScript type checker on a separate process.</p>
  4. [![npm version](https://img.shields.io/npm/v/fork-ts-checker-webpack-plugin.svg)](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin)
  5. [![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)
  6. [![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)
  7. [![downloads](http://img.shields.io/npm/dm/fork-ts-checker-webpack-plugin.svg)](https://npmjs.org/package/fork-ts-checker-webpack-plugin)
  8. [![commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
  9. [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
  10. [![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)
  11. </div>
  12. ## Installation
  13. This 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**)
  14. If 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.
  15. ```sh
  16. # with npm
  17. npm install --save-dev fork-ts-checker-webpack-plugin
  18. # with yarn
  19. yarn add --dev fork-ts-checker-webpack-plugin
  20. ```
  21. Basic webpack config (with [ts-loader](https://github.com/TypeStrong/ts-loader))
  22. ```js
  23. const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
  24. const webpackConfig = {
  25. context: __dirname, // to automatically find tsconfig.json
  26. entry: './src/index.ts',
  27. module: {
  28. rules: [
  29. {
  30. test: /\.tsx?$/,
  31. loader: 'ts-loader',
  32. options: {
  33. // disable type checker - we will use it in fork plugin
  34. transpileOnly: true
  35. }
  36. }
  37. ]
  38. },
  39. plugins: [new ForkTsCheckerWebpackPlugin()]
  40. };
  41. ```
  42. ## Motivation
  43. There was already similar solution - [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader). You can
  44. add `CheckerPlugin` and delegate checker to the separate process. The problem with `awesome-typescript-loader` was that, in our case,
  45. it was a lot slower than [ts-loader](https://github.com/TypeStrong/ts-loader) on an incremental build (~20s vs ~3s).
  46. Secondly, we used [tslint](https://palantir.github.io/tslint) and we wanted to run this, along with type checker, in a separate process.
  47. This is why this plugin was created. To provide better performance, the plugin reuses Abstract Syntax Trees between compilations and shares
  48. these trees with TSLint.
  49. ## Modules resolution
  50. It's very important to be aware that **this plugin uses [TypeScript](https://github.com/Microsoft/TypeScript)'s, not
  51. [webpack](https://github.com/webpack/webpack)'s modules resolution**. It means that you have to setup `tsconfig.json` correctly. For example
  52. if you set `files: ['./src/someFile.ts']` in `tsconfig.json`, this plugin will check only `someFile.ts` for semantic errors. It's because
  53. of 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
  54. to compile files (which traverses dependency graph during compilation) - we have a full list of files from the begin.
  55. To debug TypeScript's modules resolution, you can use `tsc --traceResolution` command.
  56. ## ESLint
  57. [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:
  58. `yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --dev`
  59. You should have an ESLint configuration file in your root project directory. Here is a sample `.eslintrc.js` configuration for a TypeScript project:
  60. ```js
  61. const path = require('path');
  62. module.exports = {
  63. parser: '@typescript-eslint/parser', // Specifies the ESLint parser
  64. extends: [
  65. 'plugin:@typescript-eslint/recommended' // Uses the recommended rules from the @typescript-eslint/eslint-plugin
  66. ],
  67. parserOptions: {
  68. project: path.resolve(__dirname, './tsconfig.json'),
  69. tsconfigRootDir: __dirname,
  70. ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
  71. sourceType: 'module', // Allows for the use of imports
  72. },
  73. rules: {
  74. // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
  75. // e.g. "@typescript-eslint/explicit-function-return-type": "off",
  76. }
  77. };
  78. ```
  79. There'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).
  80. ## Options
  81. - **tsconfig** `string`:
  82. Path to _tsconfig.json_ file. Default: `path.resolve(compiler.options.context, './tsconfig.json')`.
  83. - **compilerOptions** `object`:
  84. Allows overriding TypeScript options. Should be specified in the same format as you would do for the `compilerOptions` property in tsconfig.json. Default: `{}`.
  85. - **eslint** `true | undefined`:
  86. - If `true`, this activates eslint support.
  87. - **eslintOptions** `object`:
  88. - Options that can be used to initialise ESLint. See https://eslint.org/docs/developer-guide/nodejs-api#cliengine
  89. - **async** `boolean`:
  90. 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.
  91. 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`.
  92. - **ignoreDiagnostics** `number[]`:
  93. List of TypeScript diagnostic codes to ignore.
  94. - **ignoreLints** `string[]`:
  95. List of eslint rule names to ignore.
  96. - **ignoreLintWarnings** `boolean`:
  97. If true, will ignore all lint warnings.
  98. - **reportFiles** `string[]`:
  99. 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).
  100. ```js
  101. // in webpack.config.js
  102. new ForkTsCheckerWebpackPlugin({
  103. reportFiles: ['src/**/*.{ts,tsx}', '!src/skip.ts']
  104. });
  105. ```
  106. - **logger** `object`:
  107. Logger instance. It should be object that implements method: `error`, `warn`, `info`. Default: `console`.
  108. - **formatter** `'default' | 'codeframe' | (issue: Issue) => string)`:
  109. Formatter for issues and lints. By default uses `default` formatter. You can also pass your own formatter as a function
  110. (see `src/issue/` and `src/formatter/` for API reference).
  111. - **formatterOptions** `object`:
  112. Options passed to formatters (currently only `codeframe` - see [available options](https://babeljs.io/docs/en/next/babel-code-frame.html#options))
  113. - **silent** `boolean`:
  114. If `true`, logger will not be used. Default: `false`.
  115. - **checkSyntacticErrors** `boolean`:
  116. 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`.
  117. - **memoryLimit** `number`:
  118. Memory limit for service process in MB. If service exits with allocation failed error, increase this number. Default: `2048`.
  119. - **vue** `boolean | { enabled: boolean, compiler: string }`:
  120. If `true` or `enabled: true`, the linter and compiler will process VueJs single-file-component (.vue) files. See the
  121. [Vue section](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#vue) further down for information on how to correctly setup your project.
  122. - **useTypescriptIncrementalApi** `boolean`:
  123. 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.
  124. Don't use it together with VueJs enabled - it's not supported yet.
  125. - **measureCompilationTime** `boolean`:
  126. If true, the plugin will measure the time spent inside the compilation code. This may be useful to compare modes,
  127. especially if there are other loaders/plugins involved in the compilation. **requires Node.js >= 8.5.0**
  128. - **typescript** `string`:
  129. If supplied this is a custom path where `typescript` can be found. Defaults to `require.resolve('typescript')`.
  130. - **resolveModuleNameModule** and **resolveTypeReferenceDirectiveModule** `string`:
  131. 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:
  132. <details>
  133. <summary>Code sample</summary>
  134. ```js
  135. const { resolveModuleName } = require(`ts-pnp`);
  136. exports.resolveModuleName = (
  137. typescript,
  138. moduleName,
  139. containingFile,
  140. compilerOptions,
  141. resolutionHost
  142. ) => {
  143. return resolveModuleName(
  144. moduleName,
  145. containingFile,
  146. compilerOptions,
  147. resolutionHost,
  148. typescript.resolveModuleName
  149. );
  150. };
  151. exports.resolveTypeReferenceDirective = (
  152. typescript,
  153. moduleName,
  154. containingFile,
  155. compilerOptions,
  156. resolutionHost
  157. ) => {
  158. return resolveModuleName(
  159. moduleName,
  160. containingFile,
  161. compilerOptions,
  162. resolutionHost,
  163. typescript.resolveTypeReferenceDirective
  164. );
  165. };
  166. ```
  167. </details>
  168. ## Different behaviour in watch mode
  169. If 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.
  170. You 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.
  171. ## Notifier
  172. You 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.
  173. ## Known Issue Watching Non-Emitting Files
  174. At 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.
  175. We hope this will be resolved in future; the issue can be tracked [here](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/issues/36).
  176. ## Plugin Hooks
  177. This plugin provides some custom webpack hooks (all are sync):
  178. | Hook Access Key | Description | Params |
  179. | -------------------- | ------------------------------------------------------------------------------ | --------------------------------- |
  180. | `cancel` | Cancellation has been requested | `cancellationToken` |
  181. | `waiting` | Waiting for results | - |
  182. | `serviceBeforeStart` | Async plugin that can be used for delaying `fork-ts-checker-service-start` | - |
  183. | `serviceStart` | Service will be started | `tsconfigPath`, `memoryLimit` |
  184. | `serviceStartError` | Cannot start service | `error` |
  185. | `serviceOutOfMemory` | Service is out of memory | - |
  186. | `receive` | Plugin receives diagnostics and lints from service | `diagnostics`, `lints` |
  187. | `emit` | Service will add errors and warnings to webpack compilation ('build' mode) | `diagnostics`, `lints`, `elapsed` |
  188. | `done` | Service finished type checking and webpack finished compilation ('watch' mode) | `diagnostics`, `lints`, `elapsed` |
  189. ### Accessing plugin hooks
  190. To access plugin hooks and tap into the event, we need to use
  191. the `getCompilerHooks` static method. When we call this method with a [webpack compiler instance](https://webpack.js.org/api/node/),
  192. it returns the series of [tapable](https://github.com/webpack/tapable)
  193. hooks where you can pass in your callbacks.
  194. ```js
  195. // require the plugin
  196. const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
  197. // setup compiler with the plugin
  198. const compiler = webpack({
  199. // .. webpack config
  200. });
  201. // Optionally add the plugin to the compiler
  202. // **Don't do this if already added through configuration**
  203. new ForkTsCheckerWebpackPlugin({
  204. silent: true,
  205. async: true
  206. }).apply(compiler);
  207. // Now get the plugin hooks from compiler
  208. const tsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(compiler);
  209. // These hooks provide access to different events
  210. // =================================================== //
  211. // The properties of tsCheckerHooks corresponds to the //
  212. // Hook Access Key of the table above. //
  213. // =================================================== //
  214. // Example, if we want to run some code when plugin has received diagnostics
  215. // and lint
  216. tsCheckerHooks.receive.tap('yourListenerName', (diagnostics, lint) => {
  217. // do something with diagnostics, perhaps show custom message
  218. console.log(diagnostics);
  219. });
  220. // Say we want to show some message when plugin is waiting for typecheck results
  221. tsCheckerHooks.waiting.tap('yourListenerName', () => {
  222. console.log('waiting for typecheck results');
  223. });
  224. ```
  225. Calling `.tap()` on any hooks, requires two arguments.
  226. ##### `name` (`string`)
  227. The first argument passed to `.tap` is the name of your listener callback (`yourListenerName`).
  228. It doesn't need to correspond to anything special. It is intended to be used
  229. [internally](https://github.com/webpack/tapable#interception) as the `name` of
  230. the hook.
  231. ##### `callback` (`function`)
  232. The second argument is the callback function. Depending on the hook you are
  233. tapping into, several arguments are passed to the function. Do check the table
  234. above to find out which arguments are passed to which hooks.
  235. ### Accessing hooks on Webpack Multi-Compiler instance
  236. The above method will not work on webpack [multi compiler](https://webpack.js.org/api/node/#multicompiler)
  237. instance. The reason is `getCompilerHooks` expects (at lease as of now) the same
  238. compiler instance to be passed where the plugin was attached. So in case of
  239. multi compiler, we need to access individual compiler instances.
  240. ```js
  241. const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
  242. // setup multi compiler with the plugin
  243. const compiler = webpack([
  244. {
  245. // .. webpack config
  246. },
  247. {
  248. // .. webpack config
  249. }
  250. ]);
  251. // safely determine if instance is multi-compiler
  252. if ('compilers' in compiler) {
  253. compiler.compilers.forEach(singleCompiler => {
  254. // get plugin hooks from the single compiler instance
  255. const tsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(
  256. singleCompiler
  257. );
  258. // now access hooks just like before
  259. tsCheckerHooks.waiting.tap('yourListenerName', () => {
  260. console.log('waiting for typecheck results');
  261. });
  262. });
  263. }
  264. ```
  265. ## Vue
  266. 1. Turn on the vue option in the plugin in your webpack config:
  267. ```js
  268. new ForkTsCheckerWebpackPlugin({
  269. vue: true
  270. });
  271. ```
  272. Optionally 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)
  273. ```
  274. new ForkTsCheckerWebpackPlugin({
  275. vue: { enabled: true, compiler: 'nativescript-vue-template-compiler' }
  276. });
  277. ```
  278. 2. To activate TypeScript in your `.vue` files, you need to ensure your script tag's language attribute is set
  279. to `ts` or `tsx` (also make sure you include the `.vue` extension in all your import statements as shown below):
  280. ```html
  281. <script lang="ts">
  282. import Hello from '@/components/hello.vue';
  283. // ...
  284. </script>
  285. ```
  286. 3. Ideally you are also using `ts-loader` (in transpileOnly mode). Your Webpack config rules may look something like this:
  287. ```js
  288. {
  289. test: /\.ts$/,
  290. loader: 'ts-loader',
  291. include: [resolve('src'), resolve('test')],
  292. options: {
  293. appendTsSuffixTo: [/\.vue$/],
  294. transpileOnly: true
  295. }
  296. },
  297. {
  298. test: /\.vue$/,
  299. loader: 'vue-loader',
  300. options: vueLoaderConfig
  301. },
  302. ```
  303. 4. Ensure your `tsconfig.json` includes .vue files:
  304. ```js
  305. // tsconfig.json
  306. {
  307. "include": [
  308. "src/**/*.ts",
  309. "src/**/*.vue"
  310. ],
  311. "exclude": [
  312. "node_modules"
  313. ]
  314. }
  315. ```
  316. 5. It accepts any wildcard in your TypeScript configuration:
  317. ```js
  318. // tsconfig.json
  319. {
  320. "compilerOptions": {
  321. // ...
  322. "baseUrl": ".",
  323. "paths": {
  324. "@/*": [
  325. "src/*"
  326. ],
  327. "~/*": [
  328. "src/*"
  329. ]
  330. }
  331. }
  332. }
  333. // In a .ts or .vue file...
  334. import Hello from '@/components/hello.vue'
  335. ```
  336. 6. 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.
  337. ## Credits
  338. This plugin was created in [Realytics](https://www.realytics.io/) in 2017. Thank you for supporting Open Source.
  339. ## License
  340. MIT License