使用 Typescript 和 Webpack 进行 React
介绍
如今,React 被广泛用于创建交互式应用程序。但是,大多数应用程序都依赖于 create-react-app CLI 并使用 ES6。在本指南中,我们将介绍如何使用 Webpack 和 TypeScript 创建 React 应用程序。这样做的好处是可以更好地控制我们的项目,并且还可以获得 TypeScript 的所有好处。
创建新项目
让我们首先为我们的项目创建一个新目录。
mkdir my-sample-react-ts-webpack
cd my-sample-react-ts-webpack
我们将使用 npm 初始化我们的项目,如下所示:
npm init -y
以上将生成一个带有一些默认值的 package.json。
我们还为 webpack、typescript 和一些 React 特定模块添加一些依赖项。
npm install --save-dev webpack webpack-cli
npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom
npm install --save-dev typescript ts-loader source-map-loader
我们还可以在“my-sample-react-ts-webpack”下手动添加一些不同的文件和文件夹:
- 我们将添加 webpack.config.js 来添加 Webpack 相关的配置。
- 我们将为所有 TypeScript 配置添加 tsconfig.json。
- 添加 server.js 以启动我们的应用程序。
- 在“app”内添加一个新目录“src”。
- 我们还将在“app”内添加新目录“components”。
- 最后,我们将在“组件”中添加 App.tsx,并在组件中添加 index.tsx 和 HelloWorld.tsx。
因此,我们的文件夹结构将如下所示:
├── README.md
├── package.json
├── package-lock.json
├── server.js
├── tsconfig.json
├── webpack.config.js
├── .gitignore
└── src
└──app
└──components
├── App.tsx
├── index.tsx
├── HelloWorld.tsx
├── index.html
开始添加一些代码
我们将从 index.html 开始。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Let's learn to create a React app using Typescript and Webpack</title>
</head>
<body>
<div id="content"></div>
</body>
</html>
上述代码将创建一个带有空 div 的 HTML,其 ID 为“content”。
然后我们将向 tsconfig.json 添加一些配置。
{
"compilerOptions": {
"jsx": "react",
"module": "commonjs",
"noImplicitAny": true,
"outDir": "./build/",
"preserveConstEnums": true,
"removeComments": true,
"sourceMap": true,
"target": "es5"
},
"include": [
"./src/**/**/*"
]
}
现在,让我们向 webpack.config.js 添加一些 Webpack 配置。
const path = require('path'),
webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: ['./src/app/App.tsx', 'webpack-hot-middleware/client'],
vendor: ['react', 'react-dom']
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].bundle.js'
},
devtool: 'source-map',
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx']
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: 'ts-loader'
},
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
plugins: [
new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src', 'app', 'index.html') }),
new webpack.HotModuleReplacementPlugin()
]
}
我们还可以使用变量来根据我们是在生产环境还是开发环境运行来动态设置属性。我们的 webpack.config.js 将如下所示:
const path = require('path');
const isProduction = typeof NODE_ENV !== 'undefined' && NODE_ENV === 'production';
const mode = isProduction ? 'production' : 'development';
const devtool = isProduction ? false : 'inline-source-map';
module.exports = [
{
entry: './src/client.ts',
target: 'web',
mode,
devtool,
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
options: {
compilerOptions: {
"sourceMap": !isProduction,
}
}
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'client.js',
path: path.join(__dirname, 'dist', 'public')
}
},
{
entry: './src/server.ts',
target: 'node',
mode,
devtool,
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'server.js',
path: path.resolve(__dirname, 'dist')
},
node: {
__dirname: false,
__filename: false,
}
}
];
我们的 server.js 应该如下所示:
const path = require('path'),
express = require('express'),
webpack = require('webpack'),
webpackConfig = require('./webpack.config.js'),
app = express(),
port = process.env.PORT || 3000;app.listen(port, () => { console.log(`App is listening on port ${port}`) });app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
});let compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath, stats: { colors: true }
}));
app.use(require('webpack-hot-middleware')(compiler));
app.use(express.static(path.resolve(__dirname, 'dist')));
我们将代码添加到我们的 React 组件 HelloWorld.tsx:
import * as React from "react";
export interface HelloWorldProps { firstName: string; lastName: string; }
export const HelloWorld = (props: HelloWorldProps) => <h1>Hi there from React! Welcome {props.firstName} and {props.lastName}!</h1>;
上面的例子使用了函数式组件。我们甚至可以使用基于类的组件,如下所示:
import * as React from "react";
export interface HelloWorldProps { firstName: string; lastName: string; }
// 'HelloWorldProps' describes our props structure.
// For the state, we use the '{}' type.
export class HelloWorld extends React.Component<HelloWorldProps, {}> {
render() {
return <h1>Hi there from React! {this.props.firstName} and {this.props.lastName}!</h1>;
}
}
现在,让我们更新 index.tsx 中的代码,如下所示:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { HelloWorld } from "./components/HelloWorld";
ReactDOM.render(
<HelloWorld firstName="Chris" lastName="Parker" />,
document.getElementById("content")
);
如我们所见,我们刚刚在 index.tsx 中导入了 HelloWorld 组件。当 Webpack 看到任何扩展名为 .ts 或 .tsx 的文件时,它将使用 Typescript 加载器转译该文件。
Webpack 配置
让我们看看添加到 webpack.config.js 的不同选项。
entry - 这指定了我们应用的入口点。它可以是单个文件,也可以是我们希望包含在构建中的文件数组。
output - 包含输出配置。尝试将项目中的捆绑代码输出到磁盘时,它会查看此配置。路径表示要输出代码的输出目录,文件名表示该目录的文件名。它通常称为 bundled.js。
resolve - Webpack 根据此属性决定是否打包或跳过该文件。因此,在我们的项目中,Webpack 将考虑打包扩展名为 '.js'、'.jsx'、'.json'、'.ts' 和 '.tsx' 的文件。
模块 - 我们可以使用加载器启用 Webpack,在应用程序请求时加载特定文件。在我们的示例项目中,我们使用 ts-loader 和 source-map-loader。如果没有 ts-loader 模块,Webpack 将无法理解 App.tsx 中导入的信息,因为 HelloWorld 组件实际上是一个“tsx”文件,我们的编辑器知道它,但在导入时 Webpack 无法识别它。
import { HelloWorld } from './components/HelloWorld';
- 插件 - Webpack 有其自身的局限性。为了克服这一点,它提供了插件来扩展其功能,例如 html-webpack-plugin。此插件创建一个模板文件,该文件从 src 目录中的 index.html 文件呈现给浏览器。
TypeScript 配置
我们来看看添加到 tsconfig.json 的不同选项:
- compilation compilerOptions - 代表不同的编译器选项。
- jsx:react - 在 .tsx 文件中添加对 JSX 的支持。
- lib-向编译中添加库文件列表(例如,使用 es2015 允许我们使用 ES6 语法)。
- 模块——生成模块代码。
- noImplicitAny - 用于对隐含“任何”类型的声明引发错误
- outDir-代表输出目录。
- sourceMap-生成一个.map文件,这对于调试我们的应用程序非常有用。
- target - 表示将我们的代码转译到的目标 ECMAScript 版本(我们可以根据特定的浏览器要求添加版本)。
- include——用于指定要包含的文件列表。
建立我们的项目
现
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~