知海

TypeScript

webpackjsorg-main指南-教程

好的,我会根据提供的英文源文档,创作一份专业、结构清晰的中文技术教程。以下是教程的正文部分。


TypeScript

本指南源自 起步指南

TypeScript 是 JavaScript 的类型化超集,可编译为纯 JavaScript。在本指南中,我们将学习如何将 TypeScript 与 webpack 集成。

基本设置

首先,运行以下命令安装 TypeScript 编译器和加载器:

bash 复制代码
npm install --save-dev typescript ts-loader

现在,我们修改目录结构和配置文件:

项目结构

diff 复制代码
 webpack-demo
  ├── package.json
  ├── package-lock.json
+ ├── tsconfig.json
- ├── webpack.config.js
+ ├── webpack.config.ts
  ├── /dist
  │   ├── bundle.js
  │   └── index.html
  ├── /src
- │   ├── index.js
+ │   └── index.ts
  └── /node_modules

tsconfig.json

让我们设置一个配置文件,以支持 JSX 并将 TypeScript 编译为 ES5...

json 复制代码
{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "target": "esnext",
    "jsx": "react-jsx",
    "allowJs": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

欲了解 tsconfig.json 配置选项的更多信息,请参阅 TypeScript 文档

欲了解 webpack 配置的更多信息,请参阅 配置概念

现在,让我们配置 webpack 以处理 TypeScript:

首先,安装所需的依赖项:

bash 复制代码
npm install --save-dev ts-node @types/node

webpack.config.ts

ts 复制代码
import path from "node:path";
import { fileURLToPath } from "url";
import webpack from "webpack";

// 防止配置 `devServer` 时出现任何 TypeScript 错误
import "webpack-dev-server";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const config: webpack.Configuration = {
  entry: "./src/index.ts",
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
};

export default config;

有关如何在 TypeScript 文件 中编写配置的更多信息,请参阅相关文档。

这将指示 webpack 从 ./index.ts 文件_进入_,通过 ts-loader_加载_所有 .ts.tsx 文件,并在当前目录下_输出_一个 bundle.js 文件。

接下来,我们需要调整在 ./index.ts 中导入 lodash 的方式。由于 lodash 的类型定义不包含默认导出,因此我们需要更新导入语句。
首先,确保已安装 TypeScript 定义

bash 复制代码
npm install --save-dev @types/lodash

然后,更新文件顶部的导入语句:

./index.ts

diff 复制代码
- import _ from 'lodash';
+ import * as _ from 'lodash';

  function component() {
    const element = document.createElement('div');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    return element;
  }

  document.body.appendChild(component());

T> 若要让这些导入默认如此行为,并继续在 TypeScript 中使用 import _ from 'lodash'; 语法,请在 tsconfig.json 文件中设置 "allowSyntheticDefaultImports": true"esModuleInterop": true。这涉及到 TypeScript 的配置,此处提及仅供您参考。

webpack.config.ts 中使用 TypeScript 的方法

webpack.config.ts 中使用 TypeScript 有三种方式:

  1. 使用 webpack 内置的 Node.js 类型剥离功能(推荐):

    bash 复制代码
    webpack -c ./webpack.config.ts

    将尝试使用 Node.js 内置的 类型剥离 功能加载配置,然后尝试使用 interpretrechoir 加载配置文件(在这种情况下,您需要安装 tsxts-node 或其他工具)。

  2. 为 Node.js 使用自定义的 --import/--require

    bash 复制代码
    NODE_OPTIONS='--import=tsx --no-experimental-strip-types'  webpack -c ./webpack.config.ts
    bash 复制代码
    NODE_OPTIONS='--require=ts-node/register --no-experimental-strip-types'  webpack -c ./webpack.config.ts

    从 Node.js 22.7.0 版本开始,需要使用 --no-experimental-strip-types 标志。

  3. 为 Node.js ≥ v22.7.0 使用内置的 Node.js 转换类型功能:

    启用需要生成 JavaScript 代码的不可擦除 TypeScript 语法(例如枚举声明、参数属性)的转换。

    bash 复制代码
    NODE_OPTIONS='--experimental-transform-types' webpack --disable-interpret -c ./webpack.config.ts

TypeScript 路径别名

如果您在 tsconfig.json 中使用 compilerOptions.pathscompilerOptions.baseUrl 来创建导入别名,从 webpack 5.105 开始,webpack 可以直接通过 resolve.tsconfig 读取这些别名。这取代了 tsconfig-paths-webpack-plugin,后者不应再被使用。

resolve.tsconfig 接受 boolean | string | object

webpack.config.ts

js 复制代码
export default {
  resolve: {
    tsconfig: true, // 自动查找 tsconfig.json
  },
};

传递字符串以指向特定文件(在 monorepo 中很有用):

js 复制代码
export default {
  resolve: {
    tsconfig: "./tsconfig.app.json",
  },
};

传递一个对象以同时解析 TypeScript 项目引用

js 复制代码
export default {
  resolve: {
    tsconfig: {
      configFile: "./tsconfig.json",
      references: "auto", // 从 tsconfig 继承引用,或传递路径数组
    },
  },
};

tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

通过上述配置,@/components/Button 将解析为 src/components/Button,无需任何额外插件或在 resolve.alias 中重复别名。

tsconfig-paths-webpack-plugin 迁移

如果您当前正在使用 tsconfig-paths-webpack-plugin,可以放弃它,转而使用内置的 resolve.tsconfig 选项:

diff 复制代码
- import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';

  export default {
    resolve: {
-     plugins: [new TsconfigPathsPlugin()],
+     // 在项目根目录自动查找 tsconfig.json
+     tsconfig: true,
+
+     // 或显式指定一个
+     // tsconfig: './tsconfig.app.json'
    },
  };

然后,您可以从项目中移除该包:

bash 复制代码
npm uninstall tsconfig-paths-webpack-plugin

W> resolve.tsconfig 仅处理模块解析 —— 它不转译 TypeScript。您仍然需要 ts-loader、带有 @babel/preset-typescriptbabel-loader 或其他转译步骤。

加载器

ts-loader

我们在此指南中使用 ts-loader,因为它可以更容易地启用额外的 webpack 功能,例如导入其他 web 资源。

W> ts-loader 使用 tsc(TypeScript 编译器),并依赖于您的 tsconfig.json 配置。请确保避免将 module 设置为 "CommonJS",否则 webpack 将无法 tree-shake(摇树优化)您的代码

请注意,如果您已经在使用 babel-loader 来转译代码,您可以使用 @babel/preset-typescript 让 Babel 同时处理您的 JavaScript 和 TypeScript 文件,而无需使用额外的加载器。请记住,与 ts-loader 不同,底层的 @babel/plugin-transform-typescript 插件不执行任何类型检查。

源码映射

要了解有关源码映射的更多信息,请参阅 开发指南

要启用源码映射,我们必须配置 TypeScript 将内联源码映射输出到我们编译后的 JavaScript 文件中。必须在 TypeScript 配置中添加以下几行:

tsconfig.json

diff 复制代码
  {
    "compilerOptions": {
      "outDir": "./dist/",
+     "sourceMap": true,
      "noImplicitAny": true,
      "module": "esnext",
      "moduleResolution": "bundler",
      "target": "esnext",
      "jsx": "react-jsx",
      "allowJs": true,
  },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
  }

现在,我们需要告诉 webpack 提取这些源码映射并将其包含在最终的 bundle 中:

webpack.config.ts

diff 复制代码
 import path from "node:path";
 import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

  export default {
    entry: './src/index.ts',
+   devtool: 'inline-source-map',
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          use: 'ts-loader',
          exclude: /node_modules/,
        },
      ],
    },
    resolve: {
      extensions: [ '.tsx', '.ts', '.js' ],
    },
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist'),
    },
  };

有关更多信息,请参阅 devtool 文档

客户端类型

在 TypeScript 代码中使用 webpack 特定功能是可能的,例如 import.meta.webpack。webpack 也为它们提供了类型。添加一个 TypeScript reference 指令来声明它:

ts 复制代码
/// <reference types="webpack/module" />
console.log(import.meta.webpack); // 如果没有上述引用声明,TypeScript 将抛出错误

要为整个项目启用这些类型,请在 tsconfig.jsoncompilerOptions.types 中添加 webpack/module

diff 复制代码
  {
    "compilerOptions": {
      "types": [
+       "webpack/module"
      ]
    }
  }

使用第三方库

在从 npm 安装第三方库时,重要的是要记住安装该库的类型定义。

例如,如果我们想使用 lodash,应该运行以下命令来安装其类型定义:

bash 复制代码
npm install --save-dev @types/lodash

如果 npm 包在其包中已经包含了声明类型,则无需下载相应的 @types 包。欲了解更多信息,请参阅 TypeScript 更新日志博客

导入其他资源

要将非代码资源与 TypeScript 一起使用,我们需要延迟这些导入的类型。这需要一个 custom.d.ts 文件,它表示我们项目中 TypeScript 的自定义定义。让我们为 .svg 文件设置一个声明:

custom.d.ts

ts 复制代码
declare module "*.svg" {
  const content: any;
  export default content;
}

这里我们通过指定任何以 .svg 结尾的导入并定义模块的 contentany 来声明一个 SVG 新模块。我们可以通过将类型定义为字符串来更明确地表明它是一个 URL。同样的概念也适用于其他资源,包括 CSS、SCSS、JSON 等。

构建性能

W> 这可能会降低构建性能。

有关构建工具的更多信息,请参阅 构建性能 指南。

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。