كيفية نشر تطبيق React يستخدم التوجيه على GitHub Pages دون أخطاء 404
مقدمة: لماذا نستخدم GitHub Pages لنشر تطبيقات React؟
عند الانتهاء من بناء مشروع واجهات أمامية، تكون الخطوة التالية غالباً هي نشره على الإنترنت لعرضه على العملاء أو إضافته إلى معرض الأعمال. وهنا يبرز GitHub Pages كخيار عملي ومجاني، خاصةً للمشاريع الصغيرة والمتوسطة التي لا تتطلب خادماً خلفياً.
نشر مشروع يعتمد فقط على HTML وCSS وJavaScript عادةً يكون مباشراً. لكن عند العمل بإطار أو مكتبة مثل React، وخصوصاً إذا كان التطبيق يستخدم نظام توجيه Routing، فستحتاج إلى بعض الإعدادات الإضافية حتى يعمل المشروع المنشور كما يعمل محلياً.
في هذا الدليل، سنتعرف على الطريقة الصحيحة لنشر تطبيق React يستخدم التوجيه على GitHub Pages، مع شرح سبب ظهور أخطاء 404 وكيفية معالجتها بشكل سليم.

المتطلبات الأساسية قبل البدء
قبل تنفيذ خطوات النشر، تأكد من توفر الأدوات التالية على جهازك:
Node.jsnpmyarn- حساب على
GitHub
للتحقق من تثبيت الأدوات، افتح الطرفية ونفّذ الأوامر التالية:
npm -v
yarn -v
node -v
إذا ظهرت أرقام الإصدارات، فهذا يعني أن البيئة جاهزة. أما إذا لم تظهر، فقم بتثبيت الأدوات الناقصة أولاً.
إنشاء مشروع React جديد
سنستخدم أداة create-react-app لإنشاء مشروع مبدئي بسرعة. نفّذ الأمر التالي:
npx create-react-app starter-project
بعد اكتمال العملية، انتقل إلى مجلد المشروع وشغّله محلياً:
yarn start
إذا سار كل شيء بشكل صحيح، سيعمل التطبيق على الرابط التالي:
http://localhost:3000

رفع المشروع إلى GitHub
قبل النشر على GitHub Pages، يجب أولاً رفع المشروع إلى مستودع على GitHub. أنشئ مستودعاً جديداً بالاسم نفسه، وليكن هنا starter-project.
احرص على أن يكون المستودع عاماً لأن GitHub Pages لا يعمل في هذا السياق مع المستودعات الخاصة وفق الإعدادات التقليدية المذكورة في هذا النوع من الشرح.
بعد إنشاء المستودع، اربطه بالمشروع المحلي:
git remote add origin https://github.com/TomerPacific/starter-project
ثم اضبط الفرع الرئيسي وادفع الملفات:
git push --set-upstream origin master
بعدها يمكنك رفع بقية التعديلات بشكل طبيعي إلى المستودع.
تثبيت حزمة gh-pages وتجهيز النشر
لنشر نسخة البناء build إلى فرع gh-pages، سنستخدم الحزمة gh-pages:
yarn add gh-pages
بعد التثبيت، افتح ملف package.json وأضف أو عدّل قسم scripts بالشكل التالي:
"scripts": {
"start": "react-scripts start",
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
ثم أضف المفتاح homepage داخل الملف نفسه حتى يعرف React عنوان الجذر الصحيح بعد البناء:
{
"name": "starter-project",
"homepage": "https://tomerpacific.github.io/starter-project/",
"version": "0.1.0"
}
ما وظيفة homepage؟
هذا الحقل مهم جداً، لأنه يحدد المسار الأساسي الذي ستُبنى عليه الملفات النهائية. عند غيابه أو ضبطه بشكل خاطئ، قد تفشل الروابط أو الموارد الثابتة مثل ملفات CSS وJavaScript بعد النشر.
نشر التطبيق على GitHub Pages
بعد اكتمال الإعدادات، نفّذ أمر النشر:
npm run deploy
سيقوم هذا الأمر بما يلي:
- بناء نسخة الإنتاج عبر الأمر
build. - رفع مجلد
buildإلى فرعgh-pages. - تجهيز المشروع ليُخدم عبر
GitHub Pages.
إذا ظهر لك خطأ مرتبط بـ remote.origin.url، فغالباً السبب هو أن المستودع البعيد لم يُسمَّ origin أو لم يتم ضبطه بالشكل الصحيح.
أما إذا ظهرت كلمة Published في نهاية التنفيذ، فهذه إشارة واضحة إلى نجاح عملية النشر.
بعد ذلك، ادخل إلى إعدادات المستودع Settings ثم قسم GitHub Pages للتأكد من تفعيل النشر.


إضافة التوجيه Routing إلى تطبيق React
حتى الآن، أصبح لدينا تطبيق منشور. لكن التطبيقات الحقيقية لا تقتصر على صفحة واحدة، بل تحتوي غالباً على صفحات مثل الرئيسية، ومن نحن، واتصل بنا. وهنا نحتاج إلى نظام توجيه فعّال.
مكتبة React لا توفر التوجيه بشكل مدمج، لذلك نستخدم الحزمة react-router-dom في تطبيقات الويب.
yarn add react-router-dom
إنشاء شريط تنقل باستخدام Link
يمكنك استبدال المحتوى الافتراضي داخل ملف App.js بشريط تنقل بسيط:
<div>
<nav>
<ul id="navigation">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
</div>
العنصر Link يُستخدم بدلاً من الوسم التقليدي <a> لأنه ينفّذ الانتقال بين المسارات داخل التطبيق دون إعادة تحميل الصفحة كاملة.
إنشاء مكوّن الصفحة الرئيسية Home
import './App.css';
import React from 'react';
import logo from './logo.svg';
class Home extends React.Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Edit <code>src/App.js</code> and save to reload.</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default Home;
إنشاء صفحة About
أنشئ ملفاً جديداً باسم About.jsx وأضف إليه الكود التالي:
import React from 'react';
const divStyle = {
color: 'white'
};
class About extends React.Component {
render() {
return (
<div style={divStyle}>
<h2>About Page</h2>
<main>
<p>This section contains information about...</p>
</main>
</div>
)
}
}
export default About;
ربط المسارات بالمكوّنات عبر Route وSwitch
بعد إنشاء الصفحات، نحتاج إلى إخبار التطبيق بأي مكوّن يجب عرضه عند زيارة كل مسار. وهنا يأتي دور Route.
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
المكوّن Switch يضمن مطابقة مسار واحد فقط من بين المسارات الموجودة داخله، وهو ما يحسن منطق العرض ويمنع تضارب النتائج.
ملف App.js بعد دمج التوجيه
import './App.css';
import React from 'react';
import { Route, Switch, Link } from 'react-router-dom';
import About from './About';
import Home from './Home';
class App extends React.Component {
render() {
return (
<div className="App">
<div>
<nav>
<ul id="navigation">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
</div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</div>
);
}
}
export default App;
تغليف التطبيق داخل Router
لكي يعمل التوجيه في التطبيق، يجب تغليف الجذر الرئيسي بمكوّن Router. في كثير من المشاريع يتم استخدام BrowserRouter أولاً:
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
محلياً سيبدو كل شيء سليماً، وستعمل التنقلات الداخلية بشكل جيد. لكن المشكلة تظهر غالباً بعد النشر.
سبب ظهور أخطاء 404 بعد نشر تطبيق React
عند استخدام BrowserRouter على GitHub Pages، قد يعمل التنقل الداخلي في البداية، لكن عند تحديث الصفحة أو فتح رابط مباشر مثل /about ستظهر صفحة 404.
السبب أن GitHub Pages يتعامل مع الطلبات كملفات ومسارات فعلية على الخادم، بينما مسارات React هنا هي مسارات واجهة أمامية فقط، وليست ملفات موجودة فعلياً.
على سبيل المثال، الرابط التالي:
https://tomerpacific.github.io/starter-project/about
يجعل GitHub Pages يبحث عن مورد حقيقي في هذا المسار، ولا يجد شيئاً، فتظهر رسالة 404.
الحل الصحيح: استخدام HashRouter بدلاً من BrowserRouter
لحل هذه المشكلة، استخدم HashRouter. هذا النوع يعتمد على الجزء الذي يلي الرمز # في الرابط، وبذلك لا يحاول الخادم تفسير المسار على أنه ملف مستقل.
عدّل نقطة دخول التطبيق إلى الشكل التالي:
ReactDOM.render(
<React.StrictMode>
<HashRouter>
<App />
</HashRouter>
</React.StrictMode>,
document.getElementById('root')
);
لماذا ينجح HashRouter مع GitHub Pages؟
- لأن الجزء بعد
#لا يُرسل إلى الخادم بنفس طريقة المسار التقليدي. - لأن التنقل يصبح مُداراً بالكامل من جهة المتصفح وتطبيق
React. - لأنه يمنع أخطاء
404عند التحديث أو فتح الروابط الداخلية مباشرة.
بعد هذا التعديل، أعد تنفيذ أمر النشر:
npm run deploy
ستلاحظ أن التطبيق أصبح يعمل بصورة مستقرة دون أخطاء المسارات.
مقارنة سريعة بين BrowserRouter وHashRouter
| العنصر | BrowserRouter |
HashRouter |
|---|---|---|
| شكل الرابط | نظيف مثل /about |
يحتوي على # مثل #/about |
التوافق مع GitHub Pages |
قد يسبب 404 |
مناسب جداً |
| الحاجة إلى إعدادات خادم | نعم غالباً | لا |
| الأنسب للمواقع الثابتة | أقل ملاءمة | أكثر ملاءمة |
نصائح عملية لتحسين النشر وتجربة الاستخدام
- تأكد دائماً من صحة قيمة
homepageقبل تنفيذ النشر. - استخدم اسم
originللمستودع البعيد لتفادي مشاكل حزمةgh-pages. - اختبر التطبيق محلياً بعد أي تعديل على التوجيه.
- إذا كان المشروع موجهاً للعرض السريع أو الملف الشخصي، فإن
GitHub Pagesخيار اقتصادي وفعّال. - إذا كنت تحتاج إلى روابط نظيفة بدون
#مع دعم كامل للمسارات، ففكر في استضافة تسمح بإعادة توجيه جميع الطلبات إلى ملفindex.html.
الخلاصة التقنية
نشر تطبيق React على GitHub Pages ليس معقداً، لكن نجاح العملية يعتمد على فهم نقطتين أساسيتين: إعداد النشر عبر gh-pages، واختيار آلية التوجيه المناسبة. من الناحية التقنية، يبقى HashRouter هو الحل الأبسط والأكثر استقراراً عند استضافة تطبيقات SPA على GitHub Pages، لأنه يتجنب قيود الخادم الثابت ويمنع أخطاء 404 التي تظهر مع BrowserRouter. إذا طُبقت الخطوات السابقة بدقة، فستحصل على تطبيق منشور يعمل بكفاءة ويمكن تحديثه بسهولة مع كل إصدار جديد.