TypeScript
TypeScript هو مجموعة عليا typed من JavaScript تُصرَّف إلى JavaScript عادية. في هذا الدليل سنتعلم كيفية دمج TypeScript مع webpack.
الإعداد الأساسي
أولًا ثبّت مصرّف TypeScript والـ loader بتشغيل:
npm install --save-dev typescript ts-loaderالآن سنعدّل بنية المجلدات وملفات الإعدادات:
project
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_modulestsconfig.json
دعنا نُعد إعدادًا يدعم JSX ويصرّف TypeScript إلى ES5...
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"jsx": "react-jsx",
"allowJs": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}راجع توثيق TypeScript لمعرفة المزيد عن خيارات إعداد tsconfig.json.
لمعرفة المزيد عن إعدادات webpack، راجع مفاهيم الإعدادات.
الآن دعنا نضبط webpack للتعامل مع TypeScript:
أولًا، ثبّت الاعتماديات المطلوبة:
npm install --save-dev ts-node @types/nodewebpack.config.ts
import path from "node:path";
import { fileURLToPath } from "url";
import webpack from "webpack";
// في حال واجهت أي خطأ TypeScript عند إعداد `devServer`
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 و .tsx من خلال ts-loader، وإخراج ملف bundle.js في المجلد الحالي.
بعد ذلك، نحتاج إلى تعديل طريقة استيراد lodash في ./index.ts. بما أن تعريفات lodash لا تتضمن تصديرًا افتراضيًا، سنحتاج إلى تحديث تعليمة الاستيراد.
أولًا، تأكد من تثبيت تعريفات TypeScript:
npm install --save-dev @types/lodashثم حدّث الاستيراد في أعلى الملف:
./index.ts
- 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());طرق استخدام TypeScript في webpack.config.ts
توجد 3 طرق لاستخدام TypeScript في webpack.config.ts:
-
استخدام webpack مع ميزة Node.js المدمجة لإزالة الأنواع (موصى به):
webpack -c ./webpack.config.tsسيحاول تحميل الإعدادات باستخدام إزالة الأنواع المدمجة في Node.js، ثم سيحاول تحميل ملف الإعدادات باستخدام
interpretوrechoir(في هذه الحالة تحتاج إلى تثبيتtsxأوts-nodeأو أدوات أخرى). -
استخدام
--import/--requireمخصصين لـ Node.js:NODE_OPTIONS='--import=tsx --no-experimental-strip-types' webpack -c ./webpack.config.tsNODE_OPTIONS='--require=ts-node/register --no-experimental-strip-types' webpack -c ./webpack.config.tsالعلم
--no-experimental-strip-typesمطلوب ابتداءً من إصدار Node.js 22.7.0. -
استخدام ميزة Node.js المدمجة لتحويل الأنواع في Node.js ≥ v22.7.0:
لتفعيل تحويل صياغة TypeScript غير القابلة للمحو، والتي تتطلب توليد كود JavaScript، مثل تصريحات enum وخصائص المعاملات.
NODE_OPTIONS='--experimental-transform-types' webpack --disable-interpret -c ./webpack.config.ts
الأسماء المستعارة لمسارات TypeScript
5.105.0+إذا كنت تستخدم compilerOptions.paths أو compilerOptions.baseUrl في tsconfig.json لإنشاء أسماء مستعارة للاستيراد، فابتداءً من webpack 5.105 يمكن لـ webpack قراءة هذه الأسماء مباشرةً عبر resolve.tsconfig. هذا يستبدل tsconfig-paths-webpack-plugin، والذي لم يعد ينبغي استخدامه.
يقبل resolve.tsconfig القيم boolean | string | object:
webpack.config.ts
export default {
resolve: {
tsconfig: true, // العثور تلقائيًا على tsconfig.json
},
};مرّر string للإشارة إلى ملف محدد (مفيد في monorepos):
export default {
resolve: {
tsconfig: "./tsconfig.app.json",
},
};مرّر كائنًا لحل مراجع مشاريع TypeScript أيضًا:
export default {
resolve: {
tsconfig: {
configFile: "./tsconfig.json",
references: "auto", // وراثة references من tsconfig، أو تمرير مصفوفة من المسارات
},
},
};tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}باستخدام ما سبق، يتم حل @/components/Button إلى src/components/Button دون أي plugins إضافية أو تكرار للأسماء المستعارة في resolve.alias.
الترحيل من tsconfig-paths-webpack-plugin
إذا كنت تستخدم حاليًا tsconfig-paths-webpack-plugin، فيمكنك الاستغناء عنه لصالح خيار resolve.tsconfig المدمج:
- import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
export default {
resolve: {
- plugins: [new TsconfigPathsPlugin()],
+ // العثور تلقائيًا على tsconfig.json في جذر المشروع
+ tsconfig: true,
+
+ // أو الإشارة صراحةً إلى ملف محدد
+ // tsconfig: './tsconfig.app.json'
},
};يمكنك بعد ذلك إزالة الحزمة من مشروعك:
npm uninstall tsconfig-paths-webpack-pluginLoader
نستخدم ts-loader في هذا الدليل لأنه يجعل تفعيل ميزات webpack إضافية، مثل استيراد أصول ويب أخرى، أسهل قليلًا.
لاحظ أنك إذا كنت تستخدم بالفعل babel-loader لتصيير الكود، فيمكنك استخدام @babel/preset-typescript وترك Babel يتعامل مع ملفات JavaScript و TypeScript بدلًا من استخدام loader إضافي. ضع في اعتبارك أنه، بخلاف ts-loader، لا ينفذ الملحق الأساسي @babel/plugin-transform-typescript أي فحص للأنواع.
خرائط المصدر
لمعرفة المزيد عن خرائط المصدر، راجع دليل التطوير.
لتفعيل خرائط المصدر، يجب أن نضبط TypeScript لإخراج خرائط مصدر inline إلى ملفات JavaScript المصرّفة. يجب إضافة السطر التالي إلى إعدادات TypeScript:
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
+ "sourceMap": true,
"noImplicitAny": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "esnext",
"jsx": "react-jsx",
"allowJs": true,
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}الآن نحتاج إلى إخبار webpack باستخراج خرائط المصدر هذه وتضمينها في الحزمة النهائية:
webpack.config.ts
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 لمزيد من المعلومات.
أنواع العميل
من الممكن استخدام ميزات خاصة بـ webpack في كود TypeScript لديك، مثل import.meta.webpack. ويوفر webpack أنواعًا لها أيضًا؛ أضف توجيه reference في TypeScript للتصريح بها:
/// <reference types="webpack/module" />
console.log(import.meta.webpack); // بدون reference المصرّح به أعلاه، سيرمي TypeScript خطألتفعيل الأنواع للمشروع كاملًا، أضف webpack/module إلى compilerOptions.types في tsconfig.json:
{
"compilerOptions": {
"types": [
+ "webpack/module"
]
}
}استخدام مكتبات خارجية
عند تثبيت مكتبات خارجية من npm، من المهم تذكّر تثبيت تعريفات الأنواع لتلك المكتبة.
على سبيل المثال، إذا أردنا استخدام lodash، فيجب تشغيل الأمر التالي لتثبيت تعريفات الأنواع الخاصة بها:
npm install --save-dev @types/lodashإذا كانت حزمة npm تتضمن بالفعل typings التصريحية داخل الحزمة، فلن تكون هناك حاجة إلى تنزيل حزمة @types المقابلة. لمزيد من المعلومات، راجع مدونة سجل تغييرات TypeScript.
استيراد أصول أخرى
لاستخدام أصول غير كودية مع TypeScript، نحتاج إلى إرجاء النوع لهذه الاستيرادات. يتطلب ذلك ملف custom.d.ts يعبّر عن تعريفات مخصصة لـ TypeScript في مشروعنا. دعنا نعد تصريحًا لملفات .svg:
custom.d.ts
declare module "*.svg" {
const content: any;
export default content;
}هنا نصرّح عن وحدة جديدة لـ SVGs من خلال تحديد أي استيراد ينتهي بـ .svg وتعريف content الخاص بالوحدة على أنه any. يمكننا أن نكون أكثر صراحة بشأن كونه url عبر تعريف النوع كسلسلة نصية. ينطبق المفهوم نفسه على الأصول الأخرى، بما في ذلك CSS و SCSS و JSON وغيرها.
أداء البناء
راجع دليل أداء البناء حول أدوات البناء.



