Lesson 26-Deno Project Architecture and Engineering

Project Architecture Design

Single Page Application (SPA) and Multi-Page Application (MPA) Architecture Design

SPA Architecture Core Design

// SPA core architecture example
// src/main.ts
import { createApp } from 'vue'; // Or React, etc.
import App from './App.vue';
import router from './router';
import store from './store';

const app = createApp(App);
app.use(router);
app.use(store);
app.mount('#app');

// Router configuration (src/router/index.ts)
import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  { path: '/', component: () => import('./views/Home.vue') }, // Lazy loading
  { path: '/about', component: () => import('./views/About.vue') }
];

export default createRouter({
  history: createWebHistory(),
  routes
});

MPA Architecture Design Key Points

// MPA multi-entry configuration example (deno.json)
{
  "tasks": {
    "dev:home": "deno run --allow-net src/home/index.ts",
    "dev:about": "deno run --allow-net src/about/index.ts",
    "build:home": "deno compile --allow-net src/home/index.ts --output dist/home",
    "build:about": "deno compile --allow-net src/about/index.ts --output dist/about"
  }
}

// Multi-page HTML template (public/home.html)
<!DOCTYPE html>
<html>
<head>
  <title>Home</title>
</head>
<body>
  <div id="app"></div>
  <script src="/dist/home.js"></script>
</body>
</html>

Modularization and Componentization Design Principles

Domain-Driven Design (DDD) Module Division

src/
├── domain/          # Domain layer
   ├── user/        # User domain
      ├── model.ts # Domain model
      ├── repo.ts  # Repository interface
      └── service.ts # Domain service
   └── product/     # Product domain
├── application/     # Application layer
   ├── user/        # User use cases
   └── product/     # Product use cases
├── infrastructure/  # Infrastructure layer
   ├── db/          # Database implementation
   └── http/        # HTTP adapter
└── presentation/    # Presentation layer
    ├── web/         # Web interface
    └── api/         # API interface

Component Design Specification

// Component design example (React style)
// src/components/Button/
├── Button.tsx       # Component implementation
├── Button.types.ts  # Type definitions
├── Button.css       # Style file
└── index.ts         # Export entry

// Button.tsx
import type { ButtonProps } from './Button.types';

export const Button = ({ text, onClick }: ButtonProps) => {
  return <button onClick={onClick}>{text}</button>;
};

State Management Architecture Design

Redux Toolkit Integration Example

// src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';

export const store = configureStore({
  reducer: {
    user: userReducer
  }
});

// src/store/slices/userSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface UserState {
  name: string;
  email: string;
}

const initialState: UserState = {
  name: '',
  email: ''
};

export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    setUser(state, action: PayloadAction<UserState>) {
      return { ...state, ...action.payload };
    }
  }
});

export const { setUser } = userSlice.actions;
export default userSlice.reducer;

Zustand Lightweight Solution

// src/store/useStore.ts
import { create } from 'zustand';

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
}

export const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 }))
}));

Routing Architecture Design

Dynamic Routing Implementation

// src/router/dynamicRoutes.ts
export const generateDynamicRoutes = async () => {
  const modules = import.meta.glob('./views/*.tsx');
  const routes = Object.entries(modules).map(([path, module]) => {
    const componentName = path.split('/').pop()?.replace('.tsx', '') || '';
    return {
      path: `/${componentName.toLowerCase()}`,
      component: module
    };
  });
  return routes;
};

// Usage example
const routes = await generateDynamicRoutes();
console.log(routes); // [{path: '/home', component: () => import('./views/Home.tsx')}]

Nested Routing Configuration

// src/router/nestedRoutes.ts
import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  {
    path: '/dashboard',
    component: () => import('./layouts/DashboardLayout.vue'),
    children: [
      { path: '', component: () => import('./views/DashboardHome.vue') },
      { path: 'settings', component: () => import('./views/DashboardSettings.vue') }
    ]
  }
];

export default createRouter({
  history: createWebHistory(),
  routes
});

Project Directory Structure and Standards

Recommended Directory Structure

deno_project/
├── deps.ts          # Centralized dependency management
├── mod.ts           # Main entry file
├── src/
   ├── app.ts       # Application initialization
   ├── config/      # Configuration files
   ├── features/    # Feature modules
   ├── lib/         # Shared libraries
   ├── types/       # Type definitions
   └── utils/       # Utility functions
├── tests/           # Test files
├── web/             # Frontend resources
   ├── static/      # Static files
   └── index.html   # HTML template
├── deno.json        # Deno configuration
└── README.md

Dependency Management Standards

// deps.ts centralized dependency management
export { Application, Router } from "https://deno.land/x/oak@v17.1.0/mod.ts";
export { oakCors } from "https://deno.land/x/cors@v1.2.2/mod.ts";
export type { Context } from "https://deno.land/x/oak@v17.1.0/mod.ts";

// Use centralized imports
import { Application, oakCors } from "../deps.ts";

Engineering Toolchain

Deno Advanced Configuration (deno.json)

Complete Configuration Example

{
  "tasks": {
    "dev": "deno run --allow-net --watch src dev_server.ts",
    "test": "deno test --allow-read --coverage=cov_profile",
    "lint": "deno lint --ignore=web/assets",
    "fmt": "deno fmt --check",
    "build": "deno compile --allow-net src/main.ts --output dist/main"
  },
  "imports": {
    "react": "https://esm.sh/react@18.3.1",
    "react-dom": "https://esm.sh/react-dom@18.3.1"
  },
  "compilerOptions": {
    "lib": ["dom", "esnext"],
    "target": "es2022"
  },
  "lint": {
    "rules": {
      "tags": ["recommended"],
      "include": ["src/**/*.ts"],
      "exclude": ["src/**/*.test.ts"]
    }
  }
}

Import Map Management

// import_map.json
{
  "imports": {
    "react": "https://esm.sh/react@18.3.1",
    "react-dom": "https://esm.sh/react-dom@18.3.1",
    "lodash": "https://esm.sh/lodash@4.17.21"
  },
  "scopes": {
    "https://esm.sh/": {
      "@types/react": "https://esm.sh/@types/react@18.3.3"
    }
  }
}

Webpack Advanced Configuration

Advanced Loader Configuration

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true, // Speed up compilation
              happyPackMode: true  // Multi-threaded support
            }
          },
          {
            loader: 'eslint-loader',
            options: {
              fix: true // Auto-fix
            }
          }
        ],
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true // CSS modules
            }
          },
          'sass-loader'
        ]
      }
    ]
  }
}

Plugin Optimization Strategy

// webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // Multi-threaded compression
        extractComments: false
      })
    ],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        }
      }
    }
  },
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static' // Generate static report
    })
  ]
}

TypeScript Advanced Configuration

Strict Mode Configuration

// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}

Path Alias Configuration

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"]
    }
  }
}

// Usage example
import Button from '@/components/Button';

Code Linting Tools

ESLint Configuration

// .eslintrc.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended'
  ],
  parser: '@typescript-eslint/parser',
  rules: {
    '@typescript-eslint/no-explicit-any': 'error',
    'no-console': 'warn'
  },
  overrides: [
    {
      files: ['*.test.ts'],
      rules: {
        'no-console': 'off'
      }
    }
  ]
}

Prettier Integration

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 100
}

// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

Automated Testing Framework

Vitest Configuration Example

// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html']
    },
    setupFiles: ['./tests/setup.ts']
  }
});

// tests/setup.ts
import '@testing-library/jest-dom';

Test Case Example

// tests/button.test.tsx
import { render, screen } from '@testing-library/react';
import { Button } from '@/components/Button';

test('renders button with text', () => {
  render(<Button text="Click me" />);
  const button = screen.getByText(/click me/i);
  expect(button).toBeInTheDocument();
});

Performance Optimization and Deployment

Code Splitting and Lazy Loading

Dynamic Import Implementation

// React lazy loading example
const LazyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </React.Suspense>
  );
}

// Deno dynamic import
const module = await import(`./modules/${moduleName}.ts`);

Route-Level Code Splitting

// Vue route lazy loading
const routes = [
  {
    path: '/dashboard',
    component: () => import('./views/Dashboard.vue')
  }
];

Resource Compression and Caching

Gzip Compression Middleware

// Oak Gzip middleware
import { gzip } from "https://deno.land/std@0.224.0/encoding/gzip.ts";
import { Application } from "https://deno.land/x/oak@v17.1.0/mod.ts";

const app = new Application();

app.use(async (ctx, next) => {
  await next();
  if (ctx.response.body && ctx.request.accepts("gzip")) {
    const body = ctx.response.body instanceof Uint8Array 
      ? ctx.response.body 
      : new TextEncoder().encode(String(ctx.response.body));
    const compressed = gzip(body);
    ctx.response.body = compressed;
    ctx.response.headers.set("Content-Encoding", "gzip");
  }
});

await app.listen({ port: 8000 });

CDN Configuration Example

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.example.com/app.bundle.js"></script>
  <link rel="stylesheet" href="https://cdn.example.com/styles.css">
</head>
<body>
  <div id="app"></div>
</body>
</html>

Server-Side Rendering (SSR)

Next.js-Style SSR Implementation

// Server entry (server.ts)
import { renderToString } from 'react-dom/server';
import App from './App';
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";

await serve(async (_req) => {
  const html = renderToString(<App />);
  return new Response(`
    <!DOCTYPE html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/client.js"></script>
      </body>
    </html>
  `, {
    headers: { "Content-Type": "text/html" }
  });
});

// Client entry (client.ts)
import { hydrateRoot } from 'react-dom/client';
import App from './App';

hydrateRoot(document.getElementById('root')!, <App />);

Performance Monitoring Tools

Lighthouse CI Integration

# .github/workflows/lighthouse.yml
name: Lighthouse Audit

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: treosh/lighthouse-ci-action@v10
        with:
          urls: |
            http://localhost:8000/
            http://localhost:8000/about
          budgetPath: ./lighthouse-budget.json

Web Vitals Monitoring

// Frontend performance monitoring
import { getCLS, getFID, getLCP } from 'web-vitals';

getCLS(console.log);
getFID(console.log);
getLCP(console.log);

// Report data to analytics platform
function sendToAnalytics(metric: any) {
  const body = JSON.stringify(metric);
  navigator.sendBeacon('/analytics', body);
}

Deployment and CI/CD

Dockerized Deployment

# Dockerfile
FROM denoland/deno:2.0.0

WORKDIR /app
COPY import_map.json .
COPY deps.ts .
RUN deno cache --import-map=import_map.json deps.ts

COPY . .
RUN deno cache --import-map=import_map.json src/main.ts

EXPOSE 8000
CMD ["deno", "run", "--allow-net", "--import-map=import_map.json", "src/main.ts"]

# Build and run
# docker build -t deno-app .
# docker run -p 8000:8000 deno-app

GitHub Actions CI/CD

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: denoland/setup-deno@v2
        with:
          deno-version: "2.0.0"
      - run: deno task build
      - uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist
Share your love