今天,我們要來為系統加入一些功能。這些功能可能不會直接被使用者看到,但它們對於系統的長期健康發展有關。
首先,我們來實現一個簡單的插件系統,讓 Gym Pro 能夠更容易地擴展功能。
在 src/types/Plugin.ts
中:
export interface Plugin {
name: string;
version: string;
init: () => void;
destroy: () => void;
}
在 src/services/pluginManager.ts
中:
import { Plugin } from '../types/Plugin';
class PluginManager {
private plugins: Plugin[] = [];
registerPlugin(plugin: Plugin) {
this.plugins.push(plugin);
plugin.init();
console.log(`Plugin ${plugin.name} v${plugin.version} has been registered.`);
}
unregisterPlugin(pluginName: string) {
const index = this.plugins.findIndex(p => p.name === pluginName);
if (index !== -1) {
const plugin = this.plugins[index];
plugin.destroy();
this.plugins.splice(index, 1);
console.log(`Plugin ${plugin.name} has been unregistered.`);
}
}
getPlugin(pluginName: string): Plugin | undefined {
return this.plugins.find(p => p.name === pluginName);
}
}
export const pluginManager = new PluginManager();
在 src/plugins/customReportPlugin.ts
中:
import { Plugin } from '../types/Plugin';
const customReportPlugin: Plugin = {
name: 'Custom Report Plugin',
version: '1.0.0',
init: () => {
console.log('Custom Report Plugin initialized');
// 這裡可以增加自定義報表的邏輯
},
destroy: () => {
console.log('Custom Report Plugin destroyed');
// 這裡可以清理插件資源
}
};
export default customReportPlugin;
在 src/App.tsx
中:
import React, { useEffect } from 'react';
import { pluginManager } from './services/pluginManager';
import customReportPlugin from './plugins/customReportPlugin';
function App() {
useEffect(() => {
pluginManager.registerPlugin(customReportPlugin);
return () => {
pluginManager.unregisterPlugin(customReportPlugin.name);
};
}, []);
// ... 其他程式
}
接下來,我們來改進系統的日誌記錄功能,使用 winston 來實現更好的日誌管理。
npm install winston
在 src/services/logger.ts
中:
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
export default logger;
現在,我們可以在整個應用中使用這個日誌服務:
import logger from './services/logger';
// 在需要記錄日誌的地方
logger.info('這是一條信息日誌');
logger.error('這是一條錯誤日誌', { error: new Error('發生錯誤') });
為了讓 Gym Pro 更容易部署和維護,我們來優化打包和部署流程。我們使用 GitHub Actions 來實現自動化部署,我們也可以使用Vercel來做到自動化部屬。
在專案根目錄建立 .github/workflows/deploy.yml
檔案:
name: Deploy
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
這個工作流程會在每次推送到 main 分支時自動構建並部署應用到 GitHub Pages。
最後,我們來為 Gym Pro 增加支援國際化,使其能夠支援多種語言。我們將使用 react-i18next 來實現這個功能。
npm install react-i18next i18next
在 src/i18n.ts
中:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enTranslations from './locales/en.json';
import zhTranslations from './locales/zh.json';
i18n
.use(initReactI18next)
.init({
resources: {
en: { translation: enTranslations },
zh: { translation: zhTranslations },
},
lng: 'zh', // 預設語言
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});
export default i18n;
在 src/locales/zh.json
中:
{
"welcome": "歡迎使用 Gym Pro",
"members": "會員",
"classes": "課程",
"reports": "報表"
}
在 src/locales/en.json
中:
{
"welcome": "Welcome to Gym Pro",
"members": "Members",
"classes": "Classes",
"reports": "Reports"
}
在 src/index.tsx
中:
import React from 'react';
import ReactDOM from 'react-dom';
import './i18n';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
在組件中使用翻譯:
import React from 'react';
import { useTranslation } from 'react-i18next';
const Welcome: React.FC = () => {
const { t } = useTranslation();
return <h1>{t('welcome')}</h1>;
};
export default Welcome;
今天我們為 Gym Pro 系統增加了一些功能: