tsconfig.json 文件中 jsx 的配置项的可选值 "preserve" 和 "react-jsx" 有什么区别?

783 阅读5分钟

tsconfig.json 文件中 jsx 的配置项的可选值 "preserve" 和 "react-jsx" 有什么区别?

在 TypeScript 的 tsconfig.json 文件中,jsx 配置项用于指定 TypeScript 如何处理 JSX 语法。jsx 配置项的可选值包括 "preserve""react-jsx",它们的主要区别如下:

1. "preserve"

  • 含义:保留 JSX 语法。
  • 行为:当设置为 "preserve" 时,TypeScript 编译器会保留 JSX 语法,不会将其转化为 JavaScript 的具体调用函数。这意味着输出文件依然包含 JSX 语法。
  • 使用场景:这种设置通常用于将 TypeScript 输出传递给其他工具进行进一步处理,例如 Babel 或其他编译器,这些工具负责将 JSX 转化为 JavaScript 函数调用(如 React.createElement)。
  • 示例
    • 输入(TypeScript 文件):
      const element = <div>Hello, world!</div>;
      
    • 输出(JavaScript 文件):
      const element = <div>Hello, world!</div>;
      

2. "react-jsx"

  • 含义:将 JSX 语法转换为 React.createElement 调用。
  • 行为:当设置为 "react-jsx" 时,TypeScript 编译器会将 JSX 语法转换为 React.createElement 调用。这是 React 17 及以上版本的推荐设置,利用了新的 JSX 转换特性,减少了对导入 React 的需求。
  • 使用场景:适用于使用 React 17 及以上版本的项目,这些版本提供了新的 JSX 转换机制,使得无需在每个文件中显式导入 React
  • 示例
    • 输入(TypeScript 文件):
      const element = <div>Hello, world!</div>;
      
    • 输出(JavaScript 文件):
      const element = React.createElement("div", null, "Hello, world!");
      

综上

  • "preserve":保留 JSX 语法,适用于需要进一步处理(如使用 Babel 等)的场景。
  • "react-jsx":将 JSX 转换为 React.createElement 调用,适用于使用 React 17 及以上版本的项目,简化代码并减少显式的 React 导入。

选择哪个选项取决于你的项目配置和编译工具链的使用情况。如果你在使用 React 17 或更高版本,并希望简化导入,可以选择 "react-jsx";如果你使用其他工具进行进一步的编译,则可以选择 "preserve"

如果要实现组件的 tree-shaking , 需要选择哪种?

要实现组件的 tree-shaking,建议选择 "react-jsx"。这是因为 React 17 及以上版本的 JSX 转换机制能够更好地支持 tree-shaking。这些版本不再强制要求在每个使用 JSX 的文件中显式导入 React,从而减少了不必要的代码依赖,提高了 tree-shaking 的效率。

原因分析:

  1. 减少不必要的导入

    • 在 React 17 之前,每个使用 JSX 的文件都需要显式导入 React。这种导入会增加文件的依赖,即使某些导入没有被实际使用。
    • 使用 "react-jsx" 时,不需要显式导入 React,从而减少了不必要的代码依赖,使得 tree-shaking 更有效。
  2. 更好的支持

    • React 17 引入的新 JSX 转换机制旨在减少打包的体积和提高性能,同时更好地支持现代构建工具的 tree-shaking 功能。

设置 tsconfig.json

要启用 "react-jsx",你的 tsconfig.json 文件应进行如下配置:

{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}

示例

假设我们有以下 TypeScript 文件:

// components/Button.tsx
import React from 'react';

export const Button = () => <button>Click me</button>;

// components/UnusedComponent.tsx
import React from 'react';

export const UnusedComponent = () => <div>I'm not used</div>;

// App.tsx
import React from 'react';
import { Button } from './components/Button';

const App = () => (
  <div>
    <h1>Hello, world!</h1>
    <Button />
  </div>
);

export default App;

在使用 "react-jsx" 时,未使用的 UnusedComponent 将更容易被 tree-shaking 移除,从而减小打包体积。

配置构建工具

除了 TypeScript 配置外,还需要确保你的构建工具(如 Webpack、Rollup 等)正确配置了 tree-shaking。以 Webpack 为例,可以进行如下配置:

// webpack.config.js
module.exports = {
  // ...
  mode: 'production',
  optimization: {
    usedExports: true,
  },
  // ...
};

选择 "react-jsx" 配置不仅简化了代码,还能更有效地实现 tree-shaking,从而减少打包后的代码体积,提高应用性能。因此,对于希望实现组件 tree-shaking 的项目,推荐使用 "react-jsx"

如果指定为 preserve ,组件构建之后没有 js 文件产出,会是什么问题?

如果在 tsconfig.json 文件中将 jsx 选项指定为 "preserve",并且组件构建之后没有生成 JavaScript 文件,可能会是以下几个问题导致的:

1. 构建工具配置问题

使用 "preserve" 选项时,TypeScript 编译器不会将 JSX 转换为 JavaScript 函数调用,因此生成的文件中仍然包含 JSX 语法。通常,需要借助 Babel 或其他工具进一步处理这些保留的 JSX 语法。

  • 检查 Babel 配置: 确保你的项目使用了 Babel,并且 Babel 配置正确处理 JSX 语法。例如,确保 Babel 配置了 @babel/preset-react 预设:

    // .babelrc
    {
      "presets": ["@babel/preset-env", "@babel/preset-react"]
    }
    
  • 构建脚本: 确保构建脚本执行了 Babel 转换。使用 Webpack 或其他构建工具时,需要确保配置了合适的加载器来处理 TypeScript 和 JSX。

    // webpack.config.js
    module.exports = {
      module: {
        rules: [
          {
            test: /\.tsx?$/,
            use: 'babel-loader',
            exclude: /node_modules/,
          },
        ],
      },
    };
    

2. TypeScript 配置问题

确保 TypeScript 配置中启用了 emit 选项,允许生成输出文件。

  • tsconfig.json: 确保以下选项配置正确:

    {
      "compilerOptions": {
        "jsx": "preserve",
        "outDir": "./dist", // 指定输出目录
        "allowJs": true,
        "emitDeclarationOnly": false // 确保不仅生成类型声明
      },
      "include": ["src/**/*"]
    }
    

3. 文件输出路径问题

可能输出文件被写入了意外的路径,或者输出路径未被正确指定。

  • 检查输出目录: 确保 outDir 选项指定了正确的输出目录,并且该目录存在并可写。

    {
      "compilerOptions": {
        "outDir": "./dist"
      }
    }
    

4. 构建脚本执行问题

构建脚本是否正确执行并且输出了预期的文件。

  • 检查构建脚本: 确保构建命令正确执行,并检查是否有错误输出。

    // package.json
    {
      "scripts": {
        "build": "tsc && babel src --out-dir dist --extensions '.ts,.tsx'"
      }
    }
    

5. 文件后缀名问题

确保文件名正确使用 .tsx 后缀,且 include 选项包含了所有源文件。

  • 检查文件后缀: 确保所有 JSX 文件使用 .tsx 后缀。

    {
      "include": ["src/**/*"]
    }
    

综上所述

如果 jsx 设置为 "preserve",需要依赖 Babel 等工具进一步处理保留的 JSX 语法。确保正确配置 Babel 和 TypeScript 构建工具,并检查输出路径和文件后缀名,应该能够解决没有生成 JavaScript 文件的问题。如果问题依然存在,可以检查构建脚本的执行情况以及是否有错误输出提示。