React & Webpack


这篇指南将会教你如何将TypeScript和React还有webpack结合在一起使用。

如果你正在做一个全新的工程,可以先阅读这篇React快速上手指南

否则,我们假设已经在使用Node.jsnpm

初始化项目结构

让我们新建一个目录。
将会命名为proj,但是你可以改成任何你喜欢的名字。

mkdir proj
cd proj

我们会像下面的结构组织我们的工程:

proj/
├─ dist/
└─ src/
   └─ components/

TypeScript文件会放在src文件夹里,通过TypeScript编译器编译,然后经webpack处理,最后生成一个main.js文件放在dist目录下。
我们自定义的组件将会放在src/components文件夹下。

下面来创建基本结构:

mkdir src
cd src
mkdir components
cd ..

Webpack会帮助我们生成dist目录。

初始化工程

现在把这个目录变成npm包。

npm init -y

它会使用默认值生成一个package.json文件。

安装依赖

首先确保已经全局安装了Webpack。

npm install --save-dev webpack webpack-cli

Webpack这个工具可以将你的所有代码和可选择地将依赖捆绑成一个单独的.js文件。

现在我们添加React和React-DOM以及它们的声明文件到package.json文件里做为依赖:

npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom

使用@types/前缀表示我们额外要获取React和React-DOM的声明文件。
通常当你导入像"react"这样的路径,它会查看react包;
然而,并不是所有的包都包含了声明文件,所以TypeScript还会查看@types/react包。
你会发现我们以后将不必在意这些。

接下来,我们要添加开发时依赖ts-loadersource-map-loader

npm install --save-dev typescript ts-loader source-map-loader

这些依赖会让TypeScript和webpack在一起良好地工作。
ts-loader可以让Webpack使用TypeScript的标准配置文件tsconfig.json编译TypeScript代码。
source-map-loader使用TypeScript输出的sourcemap文件来告诉webpack何时生成自己的sourcemaps。
这就允许你在调试最终生成的文件时就好像在调试TypeScript源码一样。

请注意,ts-loader并不是唯一的TypeScript加载器。

你还可以选择awesome-typescript-loader
可以到这里查看它们之间的区别。

JS中文网 – 前端进阶资源分享 www.javascriptC.com
一个帮助开发者成长的社区,你想要的,在这里都能找到

注意我们安装TypeScript为一个开发依赖。
我们还可以使用npm link typescript来链接TypeScript到一个全局拷贝,但这不是常见用法。

添加TypeScript配置文件

我们想将TypeScript文件整合到一起 – 这包括我们写的源码和必要的声明文件。

我们需要创建一个tsconfig.json文件,它包含了输入文件列表以及编译选项。
在工程根目录下新建文件tsconfig.json文件,添加以下内容:

{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es6",
        "jsx": "react"
    }
}

你可以在这里了解更多关于tsconfig.json文件的说明。

写些代码

下面使用React写一段TypeScript代码。
首先,在src/components目录下创建一个名为Hello.tsx的文件,代码如下:

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

export const Hello = (props: HelloProps) => 

Hello from {props.compiler} and {props.framework}!

; //JS中文网 - 前端进阶资源分享 [www.javascriptC.com]

注意这个例子使用了函数组件,我们可以让它更像一点

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

// 'HelloProps' describes the shape of props.
// State is never set so we use the '{}' type.
export class Hello extends React.Component {
    render() {
        return 

Hello from {this.props.compiler} and {this.props.framework}!

; } }

接下来,在src下创建index.tsx文件,源码如下:

import * as React from "react";
import * as ReactDOM from "react-dom";

import { Hello } from "./components/Hello";

ReactDOM.render(
    ,
    document.getElementById("example")
);

我们仅仅将Hello组件导入index.tsx
注意,不同于"react""react-dom",我们使用Hello.tsx相对路径 – 这很重要。
如果不这样做,TypeScript只会尝试在node_modules文件夹里查找。

我们还需要一个页面来显示Hello组件。
在根目录proj创建一个名为index.html的文件,如下:



    
        
        Hello React!
    
    
        

需要注意一点我们是从node_modules引入的文件。
React和React-DOM的npm包里包含了独立的.js文件,你可以在页面上引入它们,这里我们为了快捷就直接引用了。
可以随意地将它们拷贝到其它目录下,或者从CDN上引用。
Facebook在CND上提供了一系列可用的React版本,你可以在这里查看更多内容

创建一个webpack配置文件

在工程根目录下创建一个webpack.config.js文件。

module.exports = {
    mode: "production",

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx"]
    },

    module: {
        rules: [
            {
                test: /\.ts(x?)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: "ts-loader"
                    }
                ]
            },
            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            {
                enforce: "pre",
                test: /\.js$/,
                loader: "source-map-loader"
            }
        ]
    },

    // When importing a module whose path matches one of the following, just
    // assume a corresponding global variable exists and use that instead.
    // This is important because it allows us to avoid bundling all of our
    // dependencies, which allows browsers to cache those libraries between builds.
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    }
};

大家可能对externals字段有所疑惑。
我们想要避免把所有的React都放到一个文件里,因为会增加编译时间并且浏览器还能够缓存没有发生改变的库文件。

理想情况下,我们只需要在浏览器里引入React模块,但是大部分浏览器还没有支持模块。
因此大部分代码库会把自己包裹在一个单独的全局变量内,比如:jQuery_
这叫做“命名空间”模式,webpack也允许我们继续使用通过这种方式写的代码库。
通过我们的设置"react": "React",webpack会神奇地将所有对"react"的导入转换成从React全局变量中加载。

你可以在这里了解更多如何配置webpack。

整合在一起

JS中文网 – 前端进阶资源分享 www.javascriptC.com
一个帮助开发者成长的社区,你想要的,在这里都能找到

执行:

npx webpack

在浏览器里打开index.html,工程应该已经可以用了!
你可以看到页面上显示着“Hello from TypeScript and React!”

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 画漫画的程序员 GitHub仓库,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界