Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify TypeScript configuration (updated) #1028

Merged
merged 3 commits into from
Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 43 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,82 +98,54 @@ Follow [these code examples](https://github.com/Grimones/cra-rhl/commit/4ed74af2

### TypeScript

When using TypeScript, Babel is not required, but React Hot Loader will not work (properly) without it.
Just add `babel-loader` into your webpack configuration, with React Hot Loader plugin.
As of version 4, React Hot Loader requires you to pass your code through [Babel](http://babeljs.io/) to transform it so that it can be hot-reloaded. This can be a pain point for TypeScript users, who usually do not need to integrate Babel as part of their build process.

There are 2 different ways to do it.
Fortunately, it's simpler than it may seem! Babel will happily parse TypeScript syntax and can act as an alternative to the TypeScript compiler, so you can safely replace `ts-loader` or `awesome-typescript-loader` in your Webpack configuration with `babel-loader`. Babel won't typecheck your code, but you can use [`fork-ts-checker-webpack-plugin`](https://github.com/Realytics/fork-ts-checker-webpack-plugin) (and/or invoke `tsc --noEmit`) as part of your build process instead.

##### Add babel AFTER typescript.
A sample configuration:

```js
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: {
babelrc: false,
plugins: ['react-hot-loader/babel'],
},
},
'ts-loader', // (or awesome-typescript-loader)
],
}
```

In this case you have to modify your `tsconfig.json`, and compile to ES6 mode, as long as React-Hot-Loader babel plugin does not understand ES5 code.

```json
// tsconfig.json
{
"module": "commonjs",
"target": "es6"
}
```

As long you cannot ship ES6 to production, you can create a `tsconfig.dev.json`, "extend" the base tsconfig and use "dev" config in dev webpack build
. Details
for [ts-loader](https://github.com/TypeStrong/ts-loader#configfile-string-defaulttsconfigjson)
, for [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader#configfilename-string-defaulttsconfigjson).

```json
{
"extends": "./tsconfig",
"compilerOptions": {
"target": "es6"
}
}
```

Keep in mind - awesome-typescript-loader [has a built in feature](https://github.com/s-panferov/awesome-typescript-loader#usebabel-boolean-defaultfalse) (`useBabel`) to _babelify_ result.

##### Add babel BEFORE typescript

> Note: this way requires babel 7 and [babel-loader@^8.0.0](https://github.com/babel/babel-loader#install)

```js
{
test: /\.tsx?$/,
use: [
'ts-loader', // (or awesome-typescript-loader)
{
loader: 'babel-loader',
options: {
plugins: [
'@babel/plugin-syntax-typescript',
'@babel/plugin-syntax-decorators',
'@babel/plugin-syntax-jsx',
'react-hot-loader/babel',
],
},
}
],
}
```

In this case you can compile to ES5. More about [typescript and react-hot-loader](https://github.com/gaearon/react-hot-loader/issues/884)

We also have a [full example running TypeScript + React Hot Loader](https://github.com/gaearon/react-hot-loader/tree/master/examples/typescript).
// ...you'll probably need to configure the usual Webpack fields like "mode" and "entry", too.
resolve: { extensions: [".ts", ".tsx", ".js", ".jsx"] },
module: {
rules: [
{
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
"@babel/preset-env",
{ targets: { browsers: "last 2 versions" } } // or whatever your project requires
],
"@babel/preset-typescript",
"@babel/preset-react"
],
plugins: [
// plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true }],
"react-hot-loader/babel"
]
}
}
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin()
]
};
```

For a full example configuration of TypeScript with React Hot Loader and newest beta version of Babel, check [here](https://github.com/gaearon/react-hot-loader/tree/master/examples/typescript).

As an alternative to this approach, it's possible to chain Webpack loaders so that your code passes through Babel and then TypeScript (or TypeScript and then Babel), but this approach is not recommended as it is more complex and may be significantly less performant. Read more [discussion here](https://github.com/gaearon/react-hot-loader/issues/884).

### Parcel

Expand Down
8 changes: 0 additions & 8 deletions examples/typescript/.babelrc

This file was deleted.

33 changes: 18 additions & 15 deletions examples/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@
"start": "webpack-dev-server --hot"
},
"devDependencies": {
"@babel/core": "^7.0.0-beta.46",
"@babel/plugin-syntax-decorators": "^7.0.0-beta.46",
"@babel/plugin-syntax-jsx": "^7.0.0-beta.46",
"@babel/plugin-syntax-typescript": "^7.0.0-beta.46",
"awesome-typescript-loader": "^3.4.1",
"@babel/core": "7.0.0-beta.51",
"@babel/plugin-proposal-class-properties": "7.0.0-beta.51",
"@babel/plugin-proposal-decorators": "7.0.0-beta.51",
"@babel/polyfill": "7.0.0-beta.51",
"@babel/preset-env": "7.0.0-beta.51",
"@babel/preset-react": "7.0.0-beta.51",
"@babel/preset-typescript": "7.0.0-beta.51",
"@types/react": "^16.4.6",
"@types/react-dom": "^16.0.6",
"babel-loader": "^8.0.0-beta.2",
"html-webpack-plugin": "^2.30.1",
"typescript": "^2.6.2",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.9.7"
"fork-ts-checker-webpack-plugin": "^0.4.2",
"html-webpack-plugin": "^3.2.0",
"typescript": "^2.9.1",
"webpack": "^4.14.0",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4"
},
"dependencies": {
"@babel/preset-env": "^7.0.0-beta.46",
"@types/react": "^16.0.31",
"@types/react-dom": "^16.0.3",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-hot-loader": "^4.1.2"
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-hot-loader": "^4.3.3"
}
}
12 changes: 8 additions & 4 deletions examples/typescript/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import * as React from 'react'
import { hot } from 'react-hot-loader'
import * as React from 'react'
import Counter from './Counter'

const App = () => (
<h1>
Hello, world.<br />
<div>
<h1>Hello, world.</ h1>
<Counter />
</h1>
</div>
)

;(async ()=>{
console.log('You have async support if you read this instead of "ReferenceError: regeneratorRuntime is not defined" error.');
})()

export default hot(module)(App)
59 changes: 43 additions & 16 deletions examples/typescript/webpack.config.babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,57 @@
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')

module.exports = {
entry: ['./src/index'],
mode: 'development',
entry: {
vendor: [
// Required to support async/await
'@babel/polyfill',
],
main: [
'./src/index',
],
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
filename: '[name].js',
},
devtool: false,
resolve: { extensions: [".ts", ".tsx", ".js", ".jsx"] },
module: {
rules: [
{
test: /\.tsx?$/,
use: ['awesome-typescript-loader', 'babel-loader'],
},
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
react: path.resolve(path.join(__dirname, './node_modules/react')),
'babel-core': path.resolve(
path.join(__dirname, './node_modules/@babel/core'),
),
},
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
"@babel/preset-env",
{ targets: { browsers: "last 2 versions" } } // or whatever your project requires
],
"@babel/preset-typescript",
"@babel/preset-react"
],
plugins: [
// plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true }],
"react-hot-loader/babel",
]
}
}
}
]
},
plugins: [new HtmlWebpackPlugin(), new webpack.NamedModulesPlugin()],
plugins: [
new ForkTsCheckerWebpackPlugin(),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin(),
]
}
Loading