Lesson 43-WinterJS Framework Integration

Project Architecture Design

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

SPA Architecture Core Implementation

// src/main.js - SPA entry file
import { createApp } from 'vue'; // Assuming Vue is used (example framework-agnostic)
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');

// src/router/index.js - SPA routing configuration
import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  {
    path: '/',
    component: () => import('@/views/Home.vue'), // Dynamic import for lazy loading
    meta: { requiresAuth: true }
  },
  {
    path: '/about',
    component: () => import('@/views/About.vue')
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

MPA Architecture Implementation

// winter.config.js - Multi-page application configuration
export default {
  pages: {
    index: {
      entry: 'src/pages/index/main.js',
      template: 'public/index.html',
      filename: 'index.html'
    },
    about: {
      entry: 'src/pages/about/main.js',
      template: 'public/about.html',
      filename: 'about.html'
    }
  }
};

// src/pages/index/main.js - Subpage entry
import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');

Modular and Component-Based Design Principles

Modular Design Practices

// src/modules/user/index.js - User module
import actions from './actions';
import mutations from './mutations';
import getters from './getters';

export default {
  namespaced: true,
  state: () => ({
    userInfo: null,
    token: ''
  }),
  actions,
  mutations,
  getters
};

// src/store/index.js - Modular Store configuration
import { createStore } from 'vuex';
import user from './modules/user';
import product from './modules/product';

export default createStore({
  modules: {
    user,
    product
  }
});

Component-Based Design Specifications

<!-- src/components/BaseButton.vue - Base component -->
<template>
  <button 
    :class="['base-button', type]"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot></slot>
  </button>
</template>

<script>
export default {
  name: 'BaseButton',
  props: {
    type: {
      type: String,
      default: 'default'
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    handleClick() {
      this.$emit('click');
    }
  }
};
</script>

<style scoped>
.base-button {
  padding: 8px 16px;
  border-radius: 4px;
}
.default {
  background-color: #fff;
  border: 1px solid #dcdfe6;
}
.primary {
  background-color: #409eff;
  color: #fff;
}
</style>

State Management Architecture Design

Redux Configuration Example

// src/store/index.js - Redux configuration
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';

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

// src/store/slices/userSlice.js - Redux Slice
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    userInfo: null,
    token: ''
  },
  reducers: {
    setUserInfo(state, action) {
      state.userInfo = action.payload;
    },
    clearUserInfo(state) {
      state.userInfo = null;
      state.token = '';
    }
  }
});

export const { setUserInfo, clearUserInfo } = userSlice.actions;
export default userSlice.reducer;

Zustand State Management

// src/stores/userStore.js - Zustand example
import create from 'zustand';

const useUserStore = create((set) => ({
  userInfo: null,
  token: '',
  setUserInfo: (userInfo) => set({ userInfo }),
  clearUserInfo: () => set({ userInfo: null, token: '' })
}));

export default useUserStore;

// Usage in component
import useUserStore from '../stores/userStore';

function Profile() {
  const { userInfo, setUserInfo } = useUserStore();
  // ...
}

Routing Architecture Design

Dynamic Routing Configuration

// src/router/index.js - Dynamic routing
import { createRouter, createWebHistory } from 'vue-router';

const loadView = (view) => {
  return () => import(`@/views/${view}.vue`);
};

const routes = [
  {
    path: '/dashboard',
    component: loadView('Dashboard'),
    children: [
      {
        path: 'analytics',
        component: loadView('DashboardAnalytics')
      },
      {
        path: 'settings',
        component: loadView('DashboardSettings')
      }
    ]
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

Nested Routing Implementation

<!-- src/views/Dashboard.vue - Parent route component -->
<template>
  <div class="dashboard">
    <sidebar />
    <router-view /> <!-- Nested route outlet -->
  </div>
</template>

<script>
import Sidebar from '@/components/Sidebar.vue';

export default {
  components: { Sidebar }
};
</script>

Project Directory Structure and Standards

winter-project/
├── public/                  # Static assets
   ├── favicon.ico
   └── index.html
├── src/
   ├── assets/              # Project assets
   ├── components/          # Shared components
   ├── composables/         # Composition functions
   ├── layouts/             # Layout components
   ├── router/              # Routing configuration
   ├── stores/              # State management
   ├── styles/              # Global styles
   ├── utils/               # Utility functions
   ├── views/               # Page components
   ├── App.vue              # Root component
   └── main.js              # Entry file
├── tests/                   # Test files
├── winter.config.js         # WinterJS configuration
├── package.winter           # Dependency configuration
└── README.md

Naming Convention Examples

# Component naming
# PascalCase
components/
  BaseButton.vue
  UserProfileCard.vue

# File naming
# kebab-case
utils/
  format-date.js
  validate-email.js

# Store naming
# camelCase
stores/
  userStore.js
  productStore.js

Engineering Toolchain

Advanced WinterJS Configuration

winter.json Configuration Example

{
  "name": "winter-project",
  "version": "1.0.0",
  "scripts": {
    "dev": "winter run --watch",
    "build": "winter bundle --prod",
    "test": "winter test"
  },
  "dependencies": {
    "vue": "^3.2.0"
  },
  "devDependencies": {
    "winter-cli": "^1.0.0"
  },
  "winter": {
    "entry": "src/main.js",
    "output": {
      "path": "dist",
      "filename": "[name].[contenthash].js"
    },
    "vite": {
      "server": {
        "port": 3000,
        "open": true
      }
    }
  }
}

Environment Variables Configuration

# .env.development
VITE_API_BASE_URL=http://localhost:3000/api

# .env.production
VITE_API_BASE_URL=https://api.winterjs.com/api

# src/config.js - Using environment variables
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;

Webpack Advanced Configuration

Custom Loader Example

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.custom$/,
        use: [
          {
            loader: path.resolve(__dirname, 'loaders/custom-loader.js'),
            options: {
              debug: true
            }
          }
        ]
      }
    ]
  }
};

// loaders/custom-loader.js
module.exports = function(source) {
  // Custom processing logic
  console.log('Custom loader processing...');
  return `export default ${JSON.stringify(source)}`;
};

Plugin Development Example

// webpack.config.js
const MyPlugin = require('./plugins/my-plugin');

module.exports = {
  plugins: [
    new MyPlugin({
      name: 'My Custom Plugin'
    })
  ]
};

// plugins/my-plugin.js
class MyPlugin {
  constructor(options) {
    this.options = options;
  }

  apply(compiler) {
    compiler.hooks.emit.tap('MyPlugin', (compilation) => {
      console.log('MyPlugin: emit hook');
      compilation.assets['custom.txt'] = {
        source: () => 'This is generated by MyPlugin',
        size: () => 25
      };
    });
  }
}

module.exports = MyPlugin;

TypeScript Advanced Configuration

tsconfig.json Strict Mode

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Path Alias Configuration

// winter.config.js
export default {
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components')
    }
  }
};

// Usage example
import BaseButton from '@/components/BaseButton';
import Header from '@components/Header';

Code Standards and Style Guidelines

ESLint Configuration

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    node: true
  },
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/typescript/recommended'
  ],
  parserOptions: {
    ecmaVersion: 2020
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off'
  }
};

Prettier Configuration

{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "all",
  "bracketSpacing": true,
  "bracketSameLine": false,
  "arrowParens": "always",
  "endOfLine": "lf"
}

Automated Testing Framework

Jest Configuration Example

// jest.config.js
module.exports = {
  preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
  testEnvironment: 'jsdom',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '^.+\\.tsx?$': 'ts-jest'
  },
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov']
};

// Example test file
import { mount } from '@vue/test-utils';
import BaseButton from '@/components/BaseButton.vue';

describe('BaseButton', () => {
  it('emits click event when clicked', async () => {
    const wrapper = mount(BaseButton);
    await wrapper.trigger('click');
    expect(wrapper.emitted('click')).toBeTruthy();
  });
});

Vitest Configuration

// vitest.config.js
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  test: {
    environment: 'jsdom',
    globals: true,
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html']
    }
  },
  resolve: {
    alias: {
      '@': '/src'
    }
  }
});

// Example test
import { describe, it, expect } from 'vitest';
import { ref } from 'vue';

describe('reactivity', () => {
  it('should track changes', () => {
    const count = ref(0);
    let dummy;
    const stop = watchEffect(() => {
      dummy = count.value;
    });
    expect(dummy).toBe(0);
    count.value++;
    expect(dummy).toBe(1);
    stop();
  });
});

Performance Optimization and Deployment

Code Splitting and Lazy Loading

Dynamic Import Implementation

// Route-level code splitting
const routes = [
  {
    path: '/dashboard',
    component: () => import(/* webpackChunkName: "dashboard" */ '@/views/Dashboard.vue')
  }
];

// Component-level lazy loading
import { defineAsyncComponent } from 'vue';

const AsyncModal = defineAsyncComponent(() =>
  import('@/components/Modal.vue')
);

export default {
  components: {
    AsyncModal
  }
};

WinterJS Code Splitting Configuration

// winter.config.js
export default {
  bundle: {
    splitting: true,
    chunkSizeWarningLimit: 1024, // 1MB
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return 'vendor';
          }
          if (id.includes('src/views')) {
            return 'views-' + id.split('src/views/')[1].split('/')[0];
          }
        }
      }
    }
  }
};

Resource Compression and Caching Strategies

Gzip Compression Configuration

// winter.config.js
import compressionWebpackPlugin from 'compression-webpack-plugin';

export default {
  configureWebpack: {
    plugins: [
      new compressionWebpackPlugin({
        algorithm: 'gzip',
        test: /\.(js|css|html|svg)$/,
        threshold: 10240, // 10KB
        minRatio: 0.8
      })
    ]
  }
};

// Nginx configuration example
/*
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_comp_level 6;
gzip_min_length 1024;
*/

CDN Configuration Example

// winter.config.js
export default {
  publicPath: process.env.NODE_ENV === 'production'
    ? 'https://cdn.winterjs.com/assets/'
    : '/'
};

// HTML usage
<script src="https://cdn.winterjs.com/assets/vendor.js"></script>
<link href="https://cdn.winterjs.com/assets/app.css" rel="stylesheet">

Server-Side Rendering (SSR) and Static Site Generation (SSG)

SSR Configuration Example

// winter.config.js
export default {
  ssr: {
    target: 'node',
    ssrManifest: true,
    renderTracked: (e) => {
      console.log('Resource tracked:', e);
    }
  }
};

// Server entry
// src/entry-server.js
import { createSSRApp } from 'vue';
import App from './App.vue';
import { createRouter } from './router';

export async function createApp() {
  const router = createRouter();
  await router.push(context.url);
  await router.isReady();

  const app = createSSRApp(App);
  app.use(router);

  return { app, router };
}

SSG Configuration Example

// winter.config.js
export default {
  ssg: {
    fallback: '404.html',
    crawler: true,
    interval: 1000
  }
};

// Generate static pages
winter build --ssg;

// Dynamic route prerendering
// src/routes/dynamic.js
export async function getStaticPaths() {
  const posts = await fetchPosts();
  return {
    paths: posts.map(post => ({
      params: { id: post.id.toString() }
    })),
    fallback: 'blocking'
  };
}

export async function getStaticProps({ params }) {
  const post = await fetchPost(params.id);
  return { props: { post } };
}

Performance Monitoring and Analysis Tools

Lighthouse Integration

// package.winter
{
  "scripts": {
    "audit": "lighthouse http://localhost:3000 --view --output=html --output-path=./reports/lighthouse.html"
  }
}

// Usage example
npm run audit

Web Vitals Monitoring

// src/main.js
import { getCLS, getFID, getLCP } from 'web-vitals';

function sendToAnalytics(metric) {
  console.log(metric);
  // Send to analytics service
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

// Custom performance metrics
export function trackPerformance() {
  const navigationTiming = performance.getEntriesByType('navigation')[0];
  console.log('Page load time:', navigationTiming.loadEventEnd);
}

Deployment and Continuous Integration

Docker Configuration Example

# Dockerfile
FROM node:16-alpine as builder

WORKDIR /app
COPY package.winter ./
RUN winterpkg install
COPY . .
RUN winter build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# nginx.conf
server {
  listen 80;
  server_name localhost;

  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }
}

CI/CD Pipeline Configuration

# .github/workflows/deploy.yml
name: WinterJS CI/CD

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: 16
    - run: npm install -g winter-cli
    - run: winterpkg install
    - run: winter test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: 16
    - run: npm install -g winter-cli
    - run: winterpkg install --production
    - run: winter build
    - uses: azure/webapps-deploy@v2
      with:
        app-name: 'winter-app'
        publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
        package: ./dist
Share your love