Build & Deployment
This document covers the build pipeline, production optimization, Progressive Web App (PWA) configuration, and deployment process for JPortal. It explains how source code is transformed into production-ready assets and deployed to GitHub Pages.
For detailed information about PWA-specific features like service workers, offline caching, and installation capabilities, see PWA Configuration. For development commands, local testing, and contribution workflows, see Development Workflow.
Build System Architecture
JPortal uses Vite as its build tool, providing fast development server startup, Hot Module Replacement (HMR), and optimized production builds. The build system is configured via vite.config.ts and integrates with TypeScript, React, and PWA tooling.
Sources: jportal/vite.config.ts1-100 jportal/package.json1-67
Build Tool Stack
| Tool | Purpose | Configuration |
|---|---|---|
| Vite | Build tool and dev server | vite.config.ts |
| TypeScript | Type checking and compilation | tsconfig.json |
| ESLint | Code linting | eslint.config.js |
| PostCSS | CSS processing | Tailwind CSS integration |
| Tailwind CSS | Utility-first CSS framework | tailwind.config.ts |
| VitePWA Plugin | Progressive Web App generation | vite.config.ts VitePWA block |
| SVGR Plugin | SVG to React component conversion | vite-plugin-svgr |
Sources: jportal/package.json45-65 jportal/vite.config.ts14-74
Build Pipeline Flow

Sources: jportal/vite.config.ts9-99 jportal/package.json8-13
NPM Scripts
The build and deployment process is orchestrated through npm scripts defined in package.json:
| Script | Command | Purpose |
|---|---|---|
dev |
vite |
Start Vite development server with HMR |
build |
vite build |
Create production build in dist/ directory |
lint |
eslint . |
Run ESLint on codebase |
preview |
vite preview |
Preview production build locally |
predeploy |
npm run build |
Hook that runs before deploy to ensure fresh build |
deploy |
gh-pages -d dist |
Deploy dist/ folder to GitHub Pages |
Sources: jportal/package.json7-13
Build Command Execution

Sources: jportal/package.json9 jportal/vite.config.ts1-99
Vite Configuration
The core build configuration is defined in vite.config.ts. Key settings include:
Base Configuration
// Base path for deployed application
base: "/jportal/"
This sets the base URL for the deployed application on GitHub Pages. All asset paths are prefixed with /jportal/.
Sources: jportal/vite.config.ts13 jportal/package.json6
Plugins
| Plugin | Purpose | Key Configuration |
|---|---|---|
@vitejs/plugin-react |
React Fast Refresh and JSX transformation | Default configuration |
vite-plugin-svgr |
Import SVGs as React components | Default configuration |
vite-plugin-pwa |
PWA manifest and service worker generation | Extensive configuration (see #6.1) |
Sources: jportal/vite.config.ts14-74
Path Aliases
resolve: {
alias: {
"@": path.resolve(__dirname, "./src")
}
}
This allows imports like import { Button } from "@/components/ui/button" instead of relative paths.
Sources: jportal/vite.config.ts75-79
Development Server Proxy
The dev server includes a proxy configuration for Cloudflare Analytics API:
server: {
proxy: {
"/api/cloudflare": {
target: "https://api.cloudflare.com",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/cloudflare/, ""),
configure: (proxy, options) => {
proxy.on("proxyReq", (proxyReq, req, res) => {
const token = env.VITE_CLOUDFLARE_API_TOKEN;
if (token) {
proxyReq.setHeader("Authorization", `Bearer ${token}`);
}
});
}
}
}
}
This proxies requests from /api/cloudflare/* to https://api.cloudflare.com/* with authentication headers injected from environment variables.
Sources: jportal/vite.config.ts80-97
PWA Build Configuration
The VitePWA plugin generates Progressive Web App assets during the build process. High-level configuration:
Service Worker Strategy
| Setting | Value | Purpose |
|---|---|---|
registerType |
"autoUpdate" |
Automatically update service worker when new version detected |
injectRegister |
"auto" |
Auto-inject service worker registration code |
devOptions.enabled |
true |
Enable PWA in development mode |
Sources: jportal/vite.config.ts18-22
Workbox Caching Configuration
workbox: {
maximumFileSizeToCacheInBytes: 30 * 1024 ** 2, // 30MB
globPatterns: ["**/*.{js,css,html,ico,png,svg,whl}"]
}
This configuration allows caching large files like Python wheel files (.whl) required for the PDF parsing functionality via Pyodide.
Sources: jportal/vite.config.ts23-25
Critical Pre-cached Assets
The following assets are explicitly pre-cached for offline functionality:
| Asset Type | URL | Purpose |
|---|---|---|
| Pyodide Runtime | https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js |
Python runtime in browser |
| jiit_marks wheel | /jportal/artifact/jiit_marks-0.2.0-py3-none-any.whl |
Custom marks parsing library |
| PyMuPDF wheel | /jportal/artifact/PyMuPDF-1.24.12-cp311-abi3-emscripten_3_1_32_wasm32.whl |
PDF parsing library |
Sources: jportal/vite.config.ts38-42 jportal/index.html17
For detailed PWA configuration including manifest structure and caching strategies, see PWA Configuration.
Deployment Process
JPortal is deployed to GitHub Pages using the gh-pages npm package. The deployment is automated through npm scripts.

Sources: jportal/package.json6-13
Deployment Steps
-
Developer triggers deployment:
npm run deploy
-
Pre-deploy hook executes:
- The
predeployscript automatically runs beforedeploy - Executes
npm run buildto create fresh production build - Ensures
dist/folder contains latest code
- The
-
gh-pages publishes:
gh-pages -d distcommand runs- Creates/updates
gh-pagesbranch in Git repository - Commits entire
dist/folder contents to this branch - Pushes to GitHub remote
-
GitHub Pages serves:
- GitHub detects changes to
gh-pagesbranch - Deploys static files to
https://codeblech.github.io/jportal - Application accessible at this URL
- GitHub detects changes to
Sources: jportal/package.json12-13
Deployment Configuration
| Setting | Value | Source |
|---|---|---|
| Homepage URL | https://codeblech.github.io/jportal |
package.json |
| Base path | /jportal/ |
vite.config.ts |
| Target branch | gh-pages |
gh-pages default |
| Source directory | dist |
deploy script |
Sources: jportal/package.json6 jportal/vite.config.ts13
Build Artifacts Structure
After running npm run build, the dist/ directory contains:
dist/
├── index.html # Main HTML entry point
├── assets/
│ ├── index-[hash].js # Main application bundle
│ ├── index-[hash].css # Compiled stylesheets
│ └── [component]-[hash].js # Code-split chunks
├── manifest.webmanifest # PWA manifest
├── sw.js # Service worker
├── workbox-[hash].js # Workbox runtime
├── pwa-icons/
│ ├── circle.ico # Favicon
│ └── j-yuvraj.svg # PWA icon
└── artifact/
├── jiit_marks-*.whl # Python wheel for marks parsing
└── PyMuPDF-*.whl # Python wheel for PDF parsing
Sources: jportal/vite.config.ts23-73 jportal/index.html5-71
HTML Entry Point
The production index.html is generated from the source template with:
- Base path injection:
<base href="/jportal/"> - Asset path rewriting: All URLs prefixed with
/jportal/ - Minification: Whitespace removed, comments stripped
- Module script injection: Bundled JavaScript files linked
Sources: jportal/index.html1-25
JavaScript Bundles
Vite creates optimized JavaScript bundles with:
- Code splitting: Dynamic imports create separate chunks
- Tree shaking: Unused exports removed
- Minification: UglifyJS/Terser compression
- Hash-based naming: Cache busting via content hashes
- Source maps: Generated for production debugging (optional)
Sources: jportal/vite.config.ts9
CSS Bundles
CSS processing includes:
- Tailwind CSS compilation: Utility classes extracted
- PostCSS transformations: Vendor prefixes, polyfills
- Minification: Whitespace and comment removal
- CSS custom properties: Theme variables preserved
- Hash-based naming: Cache invalidation
Sources: jportal/package.json47-60
External Asset Loading
JPortal loads several external assets that are critical for functionality:
Google Fonts
Fonts are loaded dynamically based on the active theme using the DynamicFontLoader component:
// Extracts font family from CSS value
extractFontFamily(fontValue: string): string | null
// Builds Google Fonts CSS URL
buildFontCssUrl(family: string, weights: string[]): string
// Injects <link> tag into document head
loadGoogleFont(family: string, weights: string[]): void
Default font weights loaded: 400, 500, 600, 700
Sources: jportal/src/utils/fonts.ts1-35 jportal/src/components/DynamicFontLoader.tsx1-34
Pyodide Runtime
The Pyodide JavaScript runtime is loaded from CDN in the HTML:
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"></script>
This enables running Python code in the browser for PDF parsing functionality in the Grades module.
Sources: jportal/index.html17
Cloudflare Web Analytics
Analytics tracking is injected via Cloudflare's beacon script:
<script defer src='https://static.cloudflareinsights.com/beacon.min.js'
data-cf-beacon='{"token": "bd095dd9dc8b402280735bc9a67d868b"}'>
</script>
Sources: jportal/index.html14-16
Build Optimization Techniques
Code Splitting Strategy
JPortal uses React Router's lazy loading for route-based code splitting:
| Route | Component | Benefit |
|---|---|---|
/attendance |
Attendance |
Loaded only when user navigates to attendance |
/grades |
Grades |
Includes heavy Pyodide dependency, split separately |
/exams |
Exams |
Independent chunk |
/subjects |
Subjects |
Independent chunk |
/profile |
Profile |
Independent chunk |
This reduces initial bundle size and improves Time to Interactive (TTI).
Sources: jportal/vite.config.ts9
Asset Optimization
| Asset Type | Optimization | Tool |
|---|---|---|
| JavaScript | Minification, tree-shaking | Vite (esbuild) |
| CSS | Minification, unused class removal | Tailwind CSS, PostCSS |
| SVG | Component conversion | vite-plugin-svgr |
| Images | Copied as-is to dist/ |
Vite static asset handling |
| Python wheels | Pre-cached in service worker | VitePWA |
Sources: jportal/vite.config.ts14-25
Caching Strategy
Three-tier caching approach:
- Browser cache: Hash-based asset names enable long-term caching
- Service worker cache: Offline-first caching via Workbox
- CDN cache: External assets cached by providers
Sources: jportal/vite.config.ts23-37
Environment Variables
The build process supports environment variables through Vite's loadEnv:
const env = loadEnv(mode, process.cwd(), '');
Currently used variables:
| Variable | Purpose | Usage |
|---|---|---|
VITE_CLOUDFLARE_API_TOKEN |
Cloudflare Analytics API authentication | Development proxy only |
Environment variables prefixed with VITE_ are exposed to client-side code.
Sources: jportal/vite.config.ts10-89 .gitignore36
Ignored Files
The .gitignore file excludes build artifacts and temporary files:
| Pattern | Description |
|---|---|
node_modules/ |
Dependency packages |
dist/ |
Production build output |
dist-ssr/ |
SSR build output (if applicable) |
dev-dist/ |
Development build artifacts |
.vite/ |
Vite cache directory |
*.local |
Local environment files |
*.env |
Environment variable files |
Sources: .gitignore1-36
Performance Metrics
Typical build output characteristics:
| Metric | Value | Description |
|---|---|---|
| Build time | ~10-30s | Varies by machine and cache state |
| Initial JS bundle | ~200-500KB | Minified, gzipped |
| Total dist/ size | ~35-50MB | Including Python wheels |
| Asset hash length | 8 characters | For cache invalidation |
| Service worker size | ~5-10KB | Workbox runtime included |
Sources: jportal/vite.config.ts24
Build Configuration Files
Key configuration files in the repository:

Sources: jportal/vite.config.ts1-100 jportal/package.json1-67